Vendor import of clang release_32 branch r168974 (effectively, 3.2 RC2):
http://llvm.org/svn/llvm-project/cfe/branches/release_32@168974
This commit is contained in:
parent
657bc3d984
commit
13cc256e40
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/vendor/clang/dist/; revision=243791 svn path=/vendor/clang/clang-release_32-r168974/; revision=243792; tag=vendor/clang/clang-release_32-r168974
1
.gitignore
vendored
1
.gitignore
vendored
@ -17,6 +17,7 @@
|
||||
*.pyc
|
||||
# vim swap files
|
||||
.*.swp
|
||||
.sw?
|
||||
|
||||
#==============================================================================#
|
||||
# Explicit files to ignore (only matches one).
|
||||
|
@ -181,16 +181,26 @@ endfunction(clang_tablegen)
|
||||
macro(add_clang_library name)
|
||||
llvm_process_sources(srcs ${ARGN})
|
||||
if(MSVC_IDE OR XCODE)
|
||||
string( REGEX MATCHALL "/[^/]+" split_path ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
list( GET split_path -1 dir)
|
||||
file( GLOB_RECURSE headers
|
||||
../../../include/clang/StaticAnalyzer${dir}/*.h
|
||||
../../../include/clang/StaticAnalyzer${dir}/*.td
|
||||
../../../include/clang/StaticAnalyzer${dir}/*.def
|
||||
../../include/clang${dir}/*.h
|
||||
../../include/clang${dir}/*.td
|
||||
../../include/clang${dir}/*.def)
|
||||
set(srcs ${srcs} ${headers})
|
||||
# Add public headers
|
||||
file(RELATIVE_PATH lib_path
|
||||
${CLANG_SOURCE_DIR}/lib/
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
if(NOT lib_path MATCHES "^[.][.]")
|
||||
file( GLOB_RECURSE headers
|
||||
${CLANG_SOURCE_DIR}/include/clang/${lib_path}/*.h
|
||||
${CLANG_SOURCE_DIR}/include/clang/${lib_path}/*.def
|
||||
)
|
||||
set_source_files_properties(${headers} PROPERTIES HEADER_FILE_ONLY ON)
|
||||
|
||||
file( GLOB_RECURSE tds
|
||||
${CLANG_SOURCE_DIR}/include/clang/${lib_path}/*.td
|
||||
)
|
||||
source_group("TableGen descriptions" FILES ${tds})
|
||||
set_source_files_properties(${tds}} PROPERTIES HEADER_FILE_ONLY ON)
|
||||
|
||||
set(srcs ${srcs} ${headers} ${tds})
|
||||
endif()
|
||||
endif(MSVC_IDE OR XCODE)
|
||||
if (MODULE)
|
||||
set(libkind MODULE)
|
||||
|
4
Makefile
4
Makefile
@ -27,6 +27,10 @@ ifeq ($(MAKECMDGOALS),libs-only)
|
||||
DIRS := $(filter-out tools docs, $(DIRS))
|
||||
OPTIONAL_DIRS :=
|
||||
endif
|
||||
ifeq ($(BUILD_CLANG_ONLY),YES)
|
||||
DIRS := $(filter-out docs unittests, $(DIRS))
|
||||
OPTIONAL_DIRS :=
|
||||
endif
|
||||
|
||||
###
|
||||
# Common Makefile code, shared by all Clang Makefiles.
|
||||
|
@ -44,7 +44,7 @@ TODO: File Manager Speedup:
|
||||
2. Instead of stat'ing the file in FileManager::getFile, check to see if
|
||||
the dir has been read. If so, fail immediately, if not, read the dir,
|
||||
then retry.
|
||||
3. Reading the dir uses the getdirentries syscall, creating an FileEntry
|
||||
3. Reading the dir uses the getdirentries syscall, creating a FileEntry
|
||||
for all files found.
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
File diff suppressed because it is too large
Load Diff
75
bindings/python/tests/cindex/test_code_completion.py
Normal file
75
bindings/python/tests/cindex/test_code_completion.py
Normal file
@ -0,0 +1,75 @@
|
||||
from clang.cindex import TranslationUnit
|
||||
|
||||
def check_completion_results(cr, expected):
|
||||
assert cr is not None
|
||||
assert len(cr.diagnostics) == 0
|
||||
|
||||
completions = [str(c) for c in cr.results]
|
||||
|
||||
for c in expected:
|
||||
assert c in completions
|
||||
|
||||
def test_code_complete():
|
||||
files = [('fake.c', """
|
||||
/// Aaa.
|
||||
int test1;
|
||||
|
||||
/// Bbb.
|
||||
void test2(void);
|
||||
|
||||
void f() {
|
||||
|
||||
}
|
||||
""")]
|
||||
|
||||
tu = TranslationUnit.from_source('fake.c', ['-std=c99'], unsaved_files=files,
|
||||
options=TranslationUnit.PARSE_INCLUDE_BRIEF_COMMENTS_IN_CODE_COMPLETION)
|
||||
|
||||
cr = tu.codeComplete('fake.c', 9, 1, unsaved_files=files, include_brief_comments=True)
|
||||
|
||||
expected = [
|
||||
"{'int', ResultType} | {'test1', TypedText} || Priority: 50 || Availability: Available || Brief comment: Aaa.",
|
||||
"{'void', ResultType} | {'test2', TypedText} | {'(', LeftParen} | {')', RightParen} || Priority: 50 || Availability: Available || Brief comment: Bbb.",
|
||||
"{'return', TypedText} || Priority: 40 || Availability: Available || Brief comment: None"
|
||||
]
|
||||
check_completion_results(cr, expected)
|
||||
|
||||
def test_code_complete_availability():
|
||||
files = [('fake.cpp', """
|
||||
class P {
|
||||
protected:
|
||||
int member;
|
||||
};
|
||||
|
||||
class Q : public P {
|
||||
public:
|
||||
using P::member;
|
||||
};
|
||||
|
||||
void f(P x, Q y) {
|
||||
x.; // member is inaccessible
|
||||
y.; // member is accessible
|
||||
}
|
||||
""")]
|
||||
|
||||
tu = TranslationUnit.from_source('fake.cpp', ['-std=c++98'], unsaved_files=files)
|
||||
|
||||
cr = tu.codeComplete('fake.cpp', 12, 5, unsaved_files=files)
|
||||
|
||||
expected = [
|
||||
"{'const', TypedText} || Priority: 40 || Availability: Available || Brief comment: None",
|
||||
"{'volatile', TypedText} || Priority: 40 || Availability: Available || Brief comment: None",
|
||||
"{'operator', TypedText} || Priority: 40 || Availability: Available || Brief comment: None",
|
||||
"{'P', TypedText} | {'::', Text} || Priority: 75 || Availability: Available || Brief comment: None",
|
||||
"{'Q', TypedText} | {'::', Text} || Priority: 75 || Availability: Available || Brief comment: None"
|
||||
]
|
||||
check_completion_results(cr, expected)
|
||||
|
||||
cr = tu.codeComplete('fake.cpp', 13, 5, unsaved_files=files)
|
||||
expected = [
|
||||
"{'P', TypedText} | {'::', Text} || Priority: 75 || Availability: Available || Brief comment: None",
|
||||
"{'P &', ResultType} | {'operator=', TypedText} | {'(', LeftParen} | {'const P &', Placeholder} | {')', RightParen} || Priority: 34 || Availability: Available || Brief comment: None",
|
||||
"{'int', ResultType} | {'member', TypedText} || Priority: 35 || Availability: NotAccessible || Brief comment: None",
|
||||
"{'void', ResultType} | {'~P', TypedText} | {'(', LeftParen} | {')', RightParen} || Priority: 34 || Availability: Available || Brief comment: None"
|
||||
]
|
||||
check_completion_results(cr, expected)
|
@ -241,3 +241,12 @@ def test_get_tokens():
|
||||
assert len(tokens) == 7
|
||||
assert tokens[0].spelling == 'int'
|
||||
assert tokens[1].spelling == 'foo'
|
||||
|
||||
def test_get_arguments():
|
||||
tu = get_tu('void foo(int i, int j);')
|
||||
foo = get_cursor(tu, 'foo')
|
||||
arguments = list(foo.get_arguments())
|
||||
|
||||
assert len(arguments) == 2
|
||||
assert arguments[0].spelling == "i"
|
||||
assert arguments[1].spelling == "j"
|
||||
|
@ -24,6 +24,9 @@
|
||||
<optional>
|
||||
<ref name="USR" />
|
||||
</optional>
|
||||
<optional>
|
||||
<ref name="Declaration" />
|
||||
</optional>
|
||||
<optional>
|
||||
<ref name="Abstract" />
|
||||
</optional>
|
||||
@ -70,6 +73,9 @@
|
||||
<ref name="USR" />
|
||||
</optional>
|
||||
<!-- TODO: Add exception specification. -->
|
||||
<optional>
|
||||
<ref name="Declaration" />
|
||||
</optional>
|
||||
<optional>
|
||||
<ref name="Abstract" />
|
||||
</optional>
|
||||
@ -79,6 +85,15 @@
|
||||
<optional>
|
||||
<ref name="Parameters" />
|
||||
</optional>
|
||||
<zeroOrMore>
|
||||
<ref name="Availability" />
|
||||
</zeroOrMore>
|
||||
<zeroOrMore>
|
||||
<ref name="Deprecated" />
|
||||
</zeroOrMore>
|
||||
<zeroOrMore>
|
||||
<ref name="Unavailable" />
|
||||
</zeroOrMore>
|
||||
<optional>
|
||||
<ref name="ResultDiscussion" />
|
||||
</optional>
|
||||
@ -105,6 +120,9 @@
|
||||
<optional>
|
||||
<ref name="USR" />
|
||||
</optional>
|
||||
<optional>
|
||||
<ref name="Declaration" />
|
||||
</optional>
|
||||
<optional>
|
||||
<ref name="Abstract" />
|
||||
</optional>
|
||||
@ -134,6 +152,9 @@
|
||||
<optional>
|
||||
<ref name="USR" />
|
||||
</optional>
|
||||
<optional>
|
||||
<ref name="Declaration" />
|
||||
</optional>
|
||||
<optional>
|
||||
<ref name="Abstract" />
|
||||
</optional>
|
||||
@ -164,6 +185,9 @@
|
||||
<optional>
|
||||
<ref name="USR" />
|
||||
</optional>
|
||||
<optional>
|
||||
<ref name="Declaration" />
|
||||
</optional>
|
||||
<optional>
|
||||
<ref name="Abstract" />
|
||||
</optional>
|
||||
@ -194,6 +218,9 @@
|
||||
<optional>
|
||||
<ref name="USR" />
|
||||
</optional>
|
||||
<optional>
|
||||
<ref name="Declaration" />
|
||||
</optional>
|
||||
<optional>
|
||||
<ref name="Abstract" />
|
||||
</optional>
|
||||
@ -224,6 +251,9 @@
|
||||
<optional>
|
||||
<ref name="USR" />
|
||||
</optional>
|
||||
<optional>
|
||||
<ref name="Declaration" />
|
||||
</optional>
|
||||
<optional>
|
||||
<ref name="Abstract" />
|
||||
</optional>
|
||||
@ -292,11 +322,18 @@
|
||||
</element>
|
||||
</define>
|
||||
|
||||
<define name="Declaration">
|
||||
<element name="Declaration">
|
||||
<!-- Non-empty text content. -->
|
||||
<data type="string"/>
|
||||
</element>
|
||||
</define>
|
||||
|
||||
<define name="Discussion">
|
||||
<element name="Discussion">
|
||||
<oneOrMore>
|
||||
<zeroOrMore>
|
||||
<ref name="TextBlockContent" />
|
||||
</oneOrMore>
|
||||
</zeroOrMore>
|
||||
</element>
|
||||
</define>
|
||||
|
||||
@ -369,6 +406,59 @@
|
||||
</element>
|
||||
</define>
|
||||
|
||||
<define name="Availability">
|
||||
<element name="Availability">
|
||||
<attribute name="distribution">
|
||||
<data type="string" />
|
||||
</attribute>
|
||||
<optional>
|
||||
<element name="IntroducedInVersion">
|
||||
<data type="string">
|
||||
<param name="pattern">\d+|\d+\.\d+|\d+\.\d+.\d+</param>
|
||||
</data>
|
||||
</element>
|
||||
</optional>
|
||||
<optional>
|
||||
<element name="DeprecatedInVersion">
|
||||
<data type="string">
|
||||
<param name="pattern">\d+|\d+\.\d+|\d+\.\d+.\d+</param>
|
||||
</data>
|
||||
</element>
|
||||
</optional>
|
||||
<optional>
|
||||
<element name="RemovedAfterVersion">
|
||||
<data type="string">
|
||||
<param name="pattern">\d+|\d+\.\d+|\d+\.\d+.\d+</param>
|
||||
</data>
|
||||
</element>
|
||||
</optional>
|
||||
<optional>
|
||||
<element name="DeprecationSummary">
|
||||
<data type="string" />
|
||||
</element>
|
||||
</optional>
|
||||
<optional>
|
||||
<ref name="Unavailable" />
|
||||
</optional>
|
||||
</element>
|
||||
</define>
|
||||
|
||||
<define name="Deprecated">
|
||||
<element name="Deprecated">
|
||||
<optional>
|
||||
<data type="string" />
|
||||
</optional>
|
||||
</element>
|
||||
</define>
|
||||
|
||||
<define name="Unavailable">
|
||||
<element name="Unavailable">
|
||||
<optional>
|
||||
<data type="string" />
|
||||
</optional>
|
||||
</element>
|
||||
</define>
|
||||
|
||||
<define name="ResultDiscussion">
|
||||
<element name="ResultDiscussion">
|
||||
<zeroOrMore>
|
||||
|
@ -45,17 +45,21 @@ The tool can detect the following types of bugs:
|
||||
Typical slowdown introduced by AddressSanitizer is <b>2x</b>.
|
||||
|
||||
<h2 id="howtobuild">How to build</h2>
|
||||
Follow the <a href="../get_started.html">clang build instructions</a>. <BR>
|
||||
Note: CMake build does not work yet.
|
||||
See <a href="http://llvm.org/bugs/show_bug.cgi?id=12272">bug 12272</a>.
|
||||
Follow the <a href="../get_started.html">clang build instructions</a>.
|
||||
CMake build is supported.<BR>
|
||||
|
||||
<h2 id="usage">Usage</h2>
|
||||
Simply compile and link your program with <tt>-faddress-sanitizer</tt> flag. <BR>
|
||||
Simply compile and link your program with <tt>-fsanitize=address</tt> flag. <BR>
|
||||
The AddressSanitizer run-time library should be linked to the final executable,
|
||||
so make sure to use <tt>clang</tt> (not <tt>ld</tt>) for the final link step.<BR>
|
||||
When linking shared libraries, the AddressSanitizer run-time is not linked,
|
||||
so <tt>-Wl,-z,defs</tt> may cause link errors (don't use it with AddressSanitizer). <BR>
|
||||
|
||||
To get a reasonable performance add <tt>-O1</tt> or higher. <BR>
|
||||
To get nicer stack traces in error messages add
|
||||
<tt>-fno-omit-frame-pointer</tt>. <BR>
|
||||
To get perfect stack traces you may need to disable inlining (just use <tt>-O1</tt>) and tail call
|
||||
elimination (</tt>-fno-optimize-sibling-calls</tt>).
|
||||
elimination (<tt>-fno-optimize-sibling-calls</tt>).
|
||||
|
||||
<pre>
|
||||
% cat example_UseAfterFree.cc
|
||||
@ -67,7 +71,15 @@ int main(int argc, char **argv) {
|
||||
</pre>
|
||||
|
||||
<pre>
|
||||
% clang -O1 -g -faddress-sanitizer -fno-omit-frame-pointer example_UseAfterFree.cc
|
||||
# Compile and link
|
||||
% clang -O1 -g -fsanitize=address -fno-omit-frame-pointer example_UseAfterFree.cc
|
||||
</pre>
|
||||
OR
|
||||
<pre>
|
||||
# Compile
|
||||
% clang -O1 -g -fsanitize=address -fno-omit-frame-pointer -c example_UseAfterFree.cc
|
||||
# Link
|
||||
% clang -g -fsanitize=address example_UseAfterFree.o
|
||||
</pre>
|
||||
|
||||
If a bug is detected, the program will print an error message to stderr and exit with a
|
||||
@ -93,6 +105,13 @@ previously allocated by thread T0 here:
|
||||
==9442== ABORTING
|
||||
</pre>
|
||||
|
||||
AddressSanitizer exits on the first detected error. This is by design.
|
||||
One reason: it makes the generated code smaller and faster (both by ~5%).
|
||||
Another reason: this makes fixing bugs unavoidable. With Valgrind, it is often
|
||||
the case that users treat Valgrind warnings as false positives
|
||||
(which they are not) and don't fix them.
|
||||
|
||||
|
||||
<h3 id="has_feature">__has_feature(address_sanitizer)</h3>
|
||||
In some cases one may need to execute different code depending on whether
|
||||
AddressSanitizer is enabled.
|
||||
@ -107,8 +126,8 @@ can be used for this purpose.
|
||||
</pre>
|
||||
|
||||
<h3 id="no_address_safety_analysis">__attribute__((no_address_safety_analysis))</h3>
|
||||
Some code should not be instrumentated by AddressSanitizer.
|
||||
One may use the function attribute
|
||||
Some code should not be instrumented by AddressSanitizer.
|
||||
One may use the function attribute
|
||||
<a href="LanguageExtensions.html#address_sanitizer">
|
||||
<tt>no_address_safety_analysis</tt></a>
|
||||
to disable instrumentation of a particular function.
|
||||
@ -118,18 +137,18 @@ Note: currently, this attribute will be lost if the function is inlined.
|
||||
|
||||
<h2 id="platforms">Supported Platforms</h2>
|
||||
AddressSanitizer is supported on
|
||||
<ul><li>Linux x86_64 (tested on Ubuntu 10.04).
|
||||
<li>MacOS 10.6 and 10.7 (i386/x86_64).
|
||||
<ul><li>Linux i386/x86_64 (tested on Ubuntu 10.04 and 12.04).
|
||||
<li>MacOS 10.6, 10.7 and 10.8 (i386/x86_64).
|
||||
</ul>
|
||||
Support for Linux i386/ARM is in progress
|
||||
Support for Linux ARM (and Android ARM) is in progress
|
||||
(it may work, but is not guaranteed too).
|
||||
|
||||
|
||||
<h2 id="limitations">Limitations</h2>
|
||||
<ul>
|
||||
<li> AddressSanitizer uses more real memory than a native run.
|
||||
How much -- depends on the allocations sizes. The smaller the
|
||||
allocations you make the bigger the overhead.
|
||||
Exact overhead depends on the allocations sizes. The smaller the
|
||||
allocations you make the bigger the overhead is.
|
||||
<li> AddressSanitizer uses more stack memory. We have seen up to 3x increase.
|
||||
<li> On 64-bit platforms AddressSanitizer maps (but not reserves)
|
||||
16+ Terabytes of virtual address space.
|
||||
@ -140,8 +159,8 @@ This means that tools like <tt>ulimit</tt> may not work as usually expected.
|
||||
|
||||
<h2 id="status">Current Status</h2>
|
||||
AddressSanitizer is fully functional on supported platforms starting from LLVM 3.1.
|
||||
However, the test suite is not fully integrated yet and we lack the testing
|
||||
process (buildbots).
|
||||
The test suite is integrated into CMake build and can be run with
|
||||
<tt>make check-asan</tt> command.
|
||||
|
||||
<h2 id="moreinfo">More Information</h2>
|
||||
<a href="http://code.google.com/p/address-sanitizer/">http://code.google.com/p/address-sanitizer</a>.
|
||||
|
@ -888,6 +888,15 @@ from non-ARC practice was acceptable because we had conservatively
|
||||
banned the synthesis in order to give ourselves exactly this
|
||||
leeway.</p></div>
|
||||
|
||||
<p>Applying <tt>__attribute__((NSObject))</tt> to a property not of
|
||||
retainable object pointer type has the same behavior it does outside
|
||||
of ARC: it requires the property type to be some sort of pointer and
|
||||
permits the use of modifiers other than <tt>assign</tt>. These
|
||||
modifiers only affect the synthesized getter and setter; direct
|
||||
accesses to the ivar (even if synthesized) still have primitive
|
||||
semantics, and the value in the ivar will not be automatically
|
||||
released during deallocation.</p>
|
||||
|
||||
</div> <!-- ownership.spelling.property -->
|
||||
|
||||
</div> <!-- ownership.spelling -->
|
||||
@ -1602,6 +1611,36 @@ implementation must be very careful to do all the other work
|
||||
that <tt>NSObject</tt>'s <tt>dealloc</tt> would, which is outside the
|
||||
scope of this document to describe.</p></div>
|
||||
|
||||
<p>The instance variables for an ARC-compiled class will be destroyed
|
||||
at some point after control enters the <tt>dealloc</tt> method for the
|
||||
root class of the class. The ordering of the destruction of instance
|
||||
variables is unspecified, both within a single class and between
|
||||
subclasses and superclasses.</p>
|
||||
|
||||
<div class="rationale"><p>Rationale: the traditional, non-ARC pattern
|
||||
for destroying instance variables is to destroy them immediately
|
||||
before calling <tt>[super dealloc]</tt>. Unfortunately, message
|
||||
sends from the superclass are quite capable of reaching methods in the
|
||||
subclass, and those methods may well read or write to those instance
|
||||
variables. Making such message sends from dealloc is generally
|
||||
discouraged, since the subclass may well rely on other invariants that
|
||||
were broken during <tt>dealloc</tt>, but it's not so inescapably
|
||||
dangerous that we felt comfortable calling it undefined behavior.
|
||||
Therefore we chose to delay destroying the instance variables to a
|
||||
point at which message sends are clearly disallowed: the point at
|
||||
which the root class's deallocation routines take over.</p>
|
||||
|
||||
<p>In most code, the difference is not observable. It can, however,
|
||||
be observed if an instance variable holds a strong reference to an
|
||||
object whose deallocation will trigger a side-effect which must be
|
||||
carefully ordered with respect to the destruction of the super class.
|
||||
Such code violates the design principle that semantically important
|
||||
behavior should be explicit. A simple fix is to clear the instance
|
||||
variable manually during <tt>dealloc</tt>; a more holistic solution is
|
||||
to move semantically important side-effects out of
|
||||
<tt>dealloc</tt> and into a separate teardown phase which can rely on
|
||||
working with well-formed objects.</p></div>
|
||||
|
||||
</div>
|
||||
|
||||
</div> <!-- misc.special_methods -->
|
||||
@ -1865,9 +1904,9 @@ and <tt>cf_unknown_transfer</tt>.</p>
|
||||
|
||||
<p>A pragma is provided to facilitate the mass annotation of interfaces:</p>
|
||||
|
||||
<pre>#pragma arc_cf_code_audited begin
|
||||
<pre>#pragma clang arc_cf_code_audited begin
|
||||
...
|
||||
#pragma arc_cf_code_audited end</pre>
|
||||
#pragma clang arc_cf_code_audited end</pre>
|
||||
|
||||
<p>All C functions declared within the extent of this pragma are
|
||||
treated as if annotated with the <tt>cf_audited_transfer</tt>
|
||||
|
@ -81,6 +81,10 @@ The compound statement body establishes a new lexical scope within that of its p
|
||||
|
||||
Local automatic (stack) variables referenced within the compound statement of a Block are imported and captured by the Block as const copies. The capture (binding) is performed at the time of the Block literal expression evaluation.
|
||||
|
||||
The compiler is not required to capture a variable if it can prove that no references to the variable will actually be evaluated. Programmers can force a variable to be captured by referencing it in a statement at the beginning of the Block, like so:
|
||||
(void) foo;
|
||||
This matters when capturing the variable has side-effects, as it can in Objective-C or C++.
|
||||
|
||||
The lifetime of variables declared in a Block is that of a function; each activation frame contains a new copy of variables declared within the local scope of the Block. Such variable declarations should be allowed anywhere [testme] rather than only when C99 parsing is requested, including for statements. [testme]
|
||||
|
||||
Block literal expressions may occur within Block literal expressions (nest) and all variables captured by any nested blocks are implicitly also captured in the scopes of their enclosing Blocks.
|
||||
@ -143,23 +147,25 @@ C++ Extensions
|
||||
|
||||
Block literal expressions within functions are extended to allow const use of C++ objects, pointers, or references held in automatic storage.
|
||||
|
||||
For example, given class Foo with member function fighter(void):
|
||||
As usual, within the block, references to captured variables become const-qualified, as if they were references to members of a const object. Note that this does not change the type of a variable of reference type.
|
||||
|
||||
For example, given a class Foo:
|
||||
Foo foo;
|
||||
Foo &fooRef = foo;
|
||||
Foo *fooPtr = &foo;
|
||||
|
||||
...a Block that used foo would import the variables as const variations:
|
||||
const Foo block_foo = foo; // const copy constructor
|
||||
const Foo &block_fooRef = fooRef;
|
||||
Foo *const block_fooPtr = fooPtr;
|
||||
A Block that referenced these variables would import the variables as const variations:
|
||||
const Foo block_foo = foo;
|
||||
Foo &block_fooRef = fooRef;
|
||||
Foo *const block_fooPtr = fooPtr;
|
||||
|
||||
Stack-local objects are copied into a Block via a copy const constructor. If no such constructor exists, it is considered an error to reference such objects from within the Block compound statements. A destructor is run as control leaves the compound statement that contains the Block literal expression.
|
||||
Captured variables are copied into the Block at the instant of evaluating the Block literal expression. They are also copied when calling Block_copy() on a Block allocated on the stack. In both cases, they are copied as if the variable were const-qualified, and it's an error if there's no such constructor.
|
||||
|
||||
If a Block originates on the stack, a const copy constructor of the stack-based Block const copy is performed when a Block_copy operation is called; when the last Block_release (or subsequently GC) occurs, a destructor is run on the heap copy.
|
||||
Captured variables in Blocks on the stack are destroyed when control leaves the compound statement that contains the Block literal expression. Captured variables in Blocks on the heap are destroyed when the reference count of the Block drops to zero.
|
||||
|
||||
Variables declared as residing in __block storage may be initially allocated in the heap or may first appear on the stack and be copied to the heap as a result of a Block_copy() operation. When copied from the stack, a normal copy constructor is used to initialize the heap-based version from the original stack version. The destructor for a const copied object is run at the normal end of scope. The destructor for any initial stack based version is also called at normal end of scope.
|
||||
Variables declared as residing in __block storage may be initially allocated in the heap or may first appear on the stack and be copied to the heap as a result of a Block_copy() operation. When copied from the stack, __block variables are copied using their normal qualification (i.e. without adding const). In C++11, __block variables are copied as x-values if that is possible, then as l-values if not; if both fail, it's an error. The destructor for any initial stack-based version is called at the variable's normal end of scope.
|
||||
|
||||
Within a member function, access to member functions and variables is done via an implicit const copy of a this pointer.
|
||||
References to 'this', as well as references to non-static members of any enclosing class, are evaluated by capturing 'this' just like a normal variable of C pointer type.
|
||||
|
||||
Member variables that are Blocks may not be overloaded by the types of their arguments.
|
||||
|
||||
|
@ -87,22 +87,14 @@ specific functionality.</p>
|
||||
|
||||
<h3 id="clang-check"><tt>clang-check</tt></h3>
|
||||
<p>This tool combines the LibTooling framework for running a Clang tool with the
|
||||
basic Clang diagnostics by syntax checking specific files in a fast, command line
|
||||
interface. It can also accept flags to re-display the diagnostics in different
|
||||
formats with different flags, suitable for use driving an IDE or editor.</p>
|
||||
basic Clang diagnostics by syntax checking specific files in a fast, command
|
||||
line interface. It can also accept flags to re-display the diagnostics in
|
||||
different formats with different flags, suitable for use driving an IDE or
|
||||
editor. Furthermore, it can be used in fixit-mode to directly apply fixit-hints
|
||||
offered by clang.</p>
|
||||
|
||||
<p>FIXME: Link to user-oriented clang-check documentation.</p>
|
||||
|
||||
<h3 id="clang-fixit"><tt>clang-fixit</tt> (Not yet implemented!)</h3>
|
||||
<p>A tool which specifically applies the Clang fix-it hint diagnostic technology
|
||||
on top of a dedicated tool. It is designed to explore alternative interfaces for
|
||||
applying fix-it hints, including automatic application, prompting users with
|
||||
options for different fixes, etc.</p>
|
||||
|
||||
<p><b>NB:</b> The clang-fixit tool is planned, but not yet implemented.</p>
|
||||
|
||||
<p>FIXME: Link to user-oriented clang-fixit documentation.</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="registerplugin">Extra Clang Tools</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
@ -77,12 +77,38 @@ $PATH. Try to run it on any .cpp file inside the LLVM source tree:</p>
|
||||
<p>If you're using vim, it's convenient to have clang-check integrated. Put this
|
||||
into your .vimrc:</p>
|
||||
<pre>
|
||||
set makeprg=clang-check\ %
|
||||
map <F5> :make<CR><CR>
|
||||
function! ClangCheckImpl(cmd)
|
||||
if &autowrite | wall | endif
|
||||
echo "Running " . a:cmd . " ..."
|
||||
let l:output = system(a:cmd)
|
||||
cexpr l:output
|
||||
cwindow
|
||||
let w:quickfix_title = a:cmd
|
||||
if v:shell_error != 0
|
||||
cc
|
||||
endif
|
||||
let g:clang_check_last_cmd = a:cmd
|
||||
endfunction
|
||||
|
||||
function! ClangCheck()
|
||||
let l:filename = expand('%')
|
||||
if l:filename =~ '\.\(cpp\|cxx\|cc\|c\)$'
|
||||
call ClangCheckImpl("clang-check " . l:filename)
|
||||
elseif exists("g:clang_check_last_cmd")
|
||||
call ClangCheckImpl(g:clang_check_last_cmd)
|
||||
else
|
||||
echo "Can't detect file's compilation arguments and no previous clang-check invocation!"
|
||||
endif
|
||||
endfunction
|
||||
|
||||
nmap <silent> <F5> :call ClangCheck()<CR><CR>
|
||||
</pre>
|
||||
|
||||
<p>When editing C++ code, hit F5 to reparse the current buffer. The output will
|
||||
go into the error window, which you can enable with <code>:cope</code>.</p>
|
||||
<p>When editing a .cpp/.cxx/.cc/.c file, hit F5 to reparse the file. In case
|
||||
the current file has a different extension (for example, .h), F5 will re-run
|
||||
the last clang-check invocation made from this vim instance (if any). The
|
||||
output will go into the error window, which is opened automatically when
|
||||
clang-check finds errors, and can be re-opened with <code>:cope</code>.</p>
|
||||
|
||||
<p>Other <code>clang-check</code> options that can be useful when working with
|
||||
clang AST:</p>
|
||||
|
@ -502,7 +502,9 @@ code, the source ranges, and the caret. However, this behavior isn't required.
|
||||
Instead of formatting and printing out the diagnostics, this implementation just
|
||||
captures and remembers the diagnostics as they fly by. Then -verify compares
|
||||
the list of produced diagnostics to the list of expected ones. If they disagree,
|
||||
it prints out its own output.
|
||||
it prints out its own output. Full documentation for the -verify mode can be
|
||||
found in the Clang API documentation for VerifyDiagnosticConsumer, <a
|
||||
href="/doxygen/classclang_1_1VerifyDiagnosticConsumer.html#details">here</a>.
|
||||
</p>
|
||||
|
||||
<p>There are many other possible implementations of this interface, and this is
|
||||
|
@ -1007,6 +1007,7 @@ struct is_convertible_to {
|
||||
<li><code>__is_convertible_to</code> (Microsoft)</li>
|
||||
<li><code>__is_empty</code> (GNU, Microsoft)</li>
|
||||
<li><code>__is_enum</code> (GNU, Microsoft)</li>
|
||||
<li><code>__is_interface_class</code> (Microsoft)</li>
|
||||
<li><code>__is_pod</code> (GNU, Microsoft)</li>
|
||||
<li><code>__is_polymorphic</code> (GNU, Microsoft)</li>
|
||||
<li><code>__is_union</code> (GNU, Microsoft)</li>
|
||||
@ -1582,7 +1583,8 @@ path between it and the next switch label.</p>
|
||||
<pre>
|
||||
// compile with -Wimplicit-fallthrough
|
||||
switch (n) {
|
||||
case 33:
|
||||
case 22:
|
||||
case 33: // no warning: no statements between case labels
|
||||
f();
|
||||
case 44: // warning: unannotated fall-through
|
||||
g();
|
||||
@ -1981,8 +1983,8 @@ int fcntl(int fd, int cmd, ...)
|
||||
|
||||
<p>Use <tt>__attribute__((pointer_with_type_tag(ptr_kind, ptr_idx,
|
||||
type_tag_idx)))</tt> on a function declaration to specify that the
|
||||
function a type tag that determines the pointee type of some other pointer
|
||||
argument.</p>
|
||||
function accepts a type tag that determines the pointee type of some other
|
||||
pointer argument.</p>
|
||||
|
||||
<p>For example:</p>
|
||||
<blockquote>
|
||||
|
130
docs/LibASTMatchers.html
Normal file
130
docs/LibASTMatchers.html
Normal file
@ -0,0 +1,130 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
|
||||
"http://www.w3.org/TR/html4/strict.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Matching the Clang AST</title>
|
||||
<link type="text/css" rel="stylesheet" href="../menu.css" />
|
||||
<link type="text/css" rel="stylesheet" href="../content.css" />
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!--#include virtual="../menu.html.incl"-->
|
||||
|
||||
<div id="content">
|
||||
|
||||
<h1>Matching the Clang AST</h1>
|
||||
<p>This document explains how to use Clang's LibASTMatchers to match interesting
|
||||
nodes of the AST and execute code that uses the matched nodes. Combined with
|
||||
<a href="LibTooling.html">LibTooling</a>, LibASTMatchers helps to write
|
||||
code-to-code transformation tools or query tools.</p>
|
||||
|
||||
<p>We assume basic knowledge about the Clang AST. See the
|
||||
<a href="IntroductionToTheClangAST.html">Introduction to the Clang AST</a> if
|
||||
you want to learn more about how the AST is structured.</p>
|
||||
|
||||
<!-- FIXME: create tutorial and link to the tutorial -->
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="intro">Introduction</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>LibASTMatchers provides a domain specific language to create predicates on Clang's
|
||||
AST. This DSL is written in and can be used from C++, allowing users to write
|
||||
a single program to both match AST nodes and access the node's C++ interface
|
||||
to extract attributes, source locations, or any other information provided on
|
||||
the AST level.</p>
|
||||
|
||||
<p>AST matchers are predicates on nodes in the AST. Matchers are created
|
||||
by calling creator functions that allow building up a tree of matchers, where
|
||||
inner matchers are used to make the match more specific.</p>
|
||||
|
||||
</p>For example, to create a matcher that matches all class or union declarations
|
||||
in the AST of a translation unit, you can call
|
||||
<a href="LibASTMatchersReference.html#recordDecl0Anchor">recordDecl()</a>.
|
||||
To narrow the match down, for example to find all class or union declarations with the name "Foo",
|
||||
insert a <a href="LibASTMatchersReference.html#hasName0Anchor">hasName</a>
|
||||
matcher: the call recordDecl(hasName("Foo")) returns a matcher that matches classes
|
||||
or unions that are named "Foo", in any namespace. By default, matchers that accept
|
||||
multiple inner matchers use an implicit <a href="LibASTMatchersReference.html#allOf0Anchor">allOf()</a>.
|
||||
This allows further narrowing down the match, for example to match all classes
|
||||
that are derived from "Bar": recordDecl(hasName("Foo"), isDerivedFrom("Bar")).</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="writing">How to create a matcher</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>With more than a thousand classes in the Clang AST, one can quickly get lost
|
||||
when trying to figure out how to create a matcher for a specific pattern. This
|
||||
section will teach you how to use a rigorous step-by-step pattern to build the
|
||||
matcher you are interested in. Note that there will always be matchers missing
|
||||
for some part of the AST. See the section about <a href="#writing">how to write
|
||||
your own AST matchers</a> later in this document.</p>
|
||||
|
||||
<p>The precondition to using the matchers is to understand how the AST
|
||||
for what you want to match looks like. The <a href="IntroductionToTheClangAST.html">Introduction to the Clang AST</a>
|
||||
teaches you how to dump a translation unit's AST into a human readable format.</p>
|
||||
|
||||
<!-- FIXME: Introduce link to ASTMatchersTutorial.html -->
|
||||
<!-- FIXME: Introduce link to ASTMatchersCookbook.html -->
|
||||
|
||||
<p>In general, the strategy to create the right matchers is:</p>
|
||||
<ol>
|
||||
<li>Find the outermost class in Clang's AST you want to match.</li>
|
||||
<li>Look at the <a href="LibASTMatchersReference.html">AST Matcher Reference</a> for matchers that either match the
|
||||
node you're interested in or narrow down attributes on the node.</li>
|
||||
<li>Create your outer match expression. Verify that it works as expected.</li>
|
||||
<li>Examine the matchers for what the next inner node you want to match is.</li>
|
||||
<li>Repeat until the matcher is finished.</li>
|
||||
</ol>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="binding">Binding nodes in match expressions</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>Matcher expressions allow you to specify which parts of the AST are interesting
|
||||
for a certain task. Often you will want to then do something with the nodes
|
||||
that were matched, like building source code transformations.</p>
|
||||
|
||||
<p>To that end, matchers that match specific AST nodes (so called node matchers)
|
||||
are bindable; for example, recordDecl(hasName("MyClass")).bind("id") will bind
|
||||
the matched recordDecl node to the string "id", to be later retrieved in the
|
||||
<a href="http://clang.llvm.org/doxygen/classclang_1_1ast__matchers_1_1MatchFinder_1_1MatchCallback.html">match callback</a>.</p>
|
||||
|
||||
<!-- FIXME: Introduce link to ASTMatchersTutorial.html -->
|
||||
<!-- FIXME: Introduce link to ASTMatchersCookbook.html -->
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="writing">Writing your own matchers</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>There are multiple different ways to define a matcher, depending on its
|
||||
type and flexibility.</p>
|
||||
<ul>
|
||||
<li><b>VariadicDynCastAllOfMatcher<Base, Derived></b><p>Those match all nodes
|
||||
of type <i>Base</i> if they can be dynamically casted to <i>Derived</i>. The
|
||||
names of those matchers are nouns, which closely resemble <i>Derived</i>.
|
||||
VariadicDynCastAllOfMatchers are the backbone of the matcher hierarchy. Most
|
||||
often, your match expression will start with one of them, and you can
|
||||
<a href="#binding">bind</a> the node they represent to ids for later processing.</p>
|
||||
<p>VariadicDynCastAllOfMatchers are callable classes that model variadic
|
||||
template functions in C++03. They take an aribtrary number of Matcher<Derived>
|
||||
and return a Matcher<Base>.</p></li>
|
||||
<li><b>AST_MATCHER_P(Type, Name, ParamType, Param)</b><p> Most matcher definitions
|
||||
use the matcher creation macros. Those define both the matcher of type Matcher<Type>
|
||||
itself, and a matcher-creation function named <i>Name</i> that takes a parameter
|
||||
of type <i>ParamType</i> and returns the corresponding matcher.</p>
|
||||
<p>There are multiple matcher definition macros that deal with polymorphic return
|
||||
values and different parameter counts. See <a href="http://clang.llvm.org/doxygen/ASTMatchersMacros_8h.html">ASTMatchersMacros.h</a>.
|
||||
</p></li>
|
||||
<li><b>Matcher creation functions</b><p>Matchers are generated by nesting
|
||||
calls to matcher creation functions. Most of the time those functions are either
|
||||
created by using VariadicDynCastAllOfMatcher or the matcher creation macros
|
||||
(see below). The free-standing functions are an indication that this matcher
|
||||
is just a combination of other matchers, as is for example the case with
|
||||
<a href="LibASTMatchersReference.html#callee1Anchor">callee</a>.</p></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
1938
docs/LibASTMatchersReference.html
Normal file
1938
docs/LibASTMatchersReference.html
Normal file
File diff suppressed because it is too large
Load Diff
@ -16,24 +16,27 @@
|
||||
<p>LibTooling is a library to support writing standalone tools based on
|
||||
Clang. This document will provide a basic walkthrough of how to write
|
||||
a tool using LibTooling.</p>
|
||||
<p>For the information on how to setup Clang Tooling for LLVM see
|
||||
<a href="HowToSetupToolingForLLVM.html">HowToSetupToolingForLLVM.html</a></p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="intro">Introduction</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>Tools built with LibTooling, like Clang Plugins, run FrontendActions over
|
||||
code. <!-- See FIXME for a tutorial on how to write FrontendActions. -->
|
||||
<p>Tools built with LibTooling, like Clang Plugins, run
|
||||
<code>FrontendActions</code> over code.
|
||||
<!-- See FIXME for a tutorial on how to write FrontendActions. -->
|
||||
In this tutorial, we'll demonstrate the different ways of running clang's
|
||||
SyntaxOnlyAction, which runs a quick syntax check, over a bunch of
|
||||
<code>SyntaxOnlyAction</code>, which runs a quick syntax check, over a bunch of
|
||||
code.</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="runoncode">Parsing a code snippet in memory.</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>If you ever wanted to run a FrontendAction over some sample code, for example
|
||||
to unit test parts of the Clang AST, runToolOnCode is what you looked for. Let
|
||||
me give you an example:
|
||||
<p>If you ever wanted to run a <code>FrontendAction</code> over some sample
|
||||
code, for example to unit test parts of the Clang AST,
|
||||
<code>runToolOnCode</code> is what you looked for. Let me give you an example:
|
||||
<pre>
|
||||
#include "clang/Tooling/Tooling.h"
|
||||
|
||||
@ -48,53 +51,44 @@ me give you an example:
|
||||
<h2 id="standalonetool">Writing a standalone tool.</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>Once you unit tested your FrontendAction to the point where it cannot
|
||||
possibly break, it's time to create a standalone tool. For a standalone tool
|
||||
to run clang, it first needs to figure out what command line arguments to use
|
||||
for a specified file. To that end we create a CompilationDatabase.</p>
|
||||
<p>Once you unit tested your <code>FrontendAction</code> to the point where it
|
||||
cannot possibly break, it's time to create a standalone tool. For a standalone
|
||||
tool to run clang, it first needs to figure out what command line arguments to
|
||||
use for a specified file. To that end we create a
|
||||
<code>CompilationDatabase</code>. There are different ways to create a
|
||||
compilation database, and we need to support all of them depending on
|
||||
command-line options. There's the <code>CommonOptionsParser</code> class
|
||||
that takes the responsibility to parse command-line parameters related to
|
||||
compilation databases and inputs, so that all tools share the implementation.
|
||||
</p>
|
||||
|
||||
<h3 id="compilationdb">Creating a compilation database.</h3>
|
||||
<p>CompilationDatabase provides static factory functions to help with parsing
|
||||
compile commands from a build directory or the command line. The following code
|
||||
allows for both explicit specification of a compile command line, as well as
|
||||
retrieving the compile commands lines from a database.
|
||||
<h3 id="parsingcommonoptions">Parsing common tools options.</h3>
|
||||
<p><code>CompilationDatabase</code> can be read from a build directory or the
|
||||
command line. Using <code>CommonOptionsParser</code> allows for explicit
|
||||
specification of a compile command line, specification of build path using the
|
||||
<code>-p</code> command-line option, and automatic location of the compilation
|
||||
database using source files paths.
|
||||
<pre>
|
||||
#include "clang/Tooling/CommonOptionsParser.h"
|
||||
|
||||
using namespace clang::tooling;
|
||||
|
||||
int main(int argc, const char **argv) {
|
||||
// First, try to create a fixed compile command database from the command line
|
||||
// arguments.
|
||||
llvm::OwningPtr<CompilationDatabase> Compilations(
|
||||
FixedCompilationDatabase::loadFromCommandLine(argc, argv));
|
||||
// CommonOptionsParser constructor will parse arguments and create a
|
||||
// CompilationDatabase. In case of error it will terminate the program.
|
||||
CommonOptionsParser OptionsParser(argc, argv);
|
||||
|
||||
// Next, use normal llvm command line parsing to get the tool specific
|
||||
// parameters.
|
||||
cl::ParseCommandLineOptions(argc, argv);
|
||||
|
||||
if (!Compilations) {
|
||||
// In case the user did not specify the compile command line via positional
|
||||
// command line arguments after "--", try to load the compile commands from
|
||||
// a database in the specified build directory or auto-detect it from a
|
||||
// source file.
|
||||
std::string ErrorMessage;
|
||||
if (!BuildPath.empty()) {
|
||||
Compilations.reset(
|
||||
CompilationDatabase::autoDetectFromDirectory(BuildPath, ErrorMessage));
|
||||
} else {
|
||||
Compilations.reset(CompilationDatabase::autoDetectFromSource(
|
||||
SourcePaths[0], ErrorMessage));
|
||||
}
|
||||
// If there is still no valid compile command database, we don't know how
|
||||
// to run the tool.
|
||||
if (!Compilations)
|
||||
llvm::report_fatal_error(ErrorMessage);
|
||||
}
|
||||
// Use OptionsParser.GetCompilations() and OptionsParser.GetSourcePathList()
|
||||
// to retrieve CompilationDatabase and the list of input file paths.
|
||||
}
|
||||
</pre>
|
||||
</p>
|
||||
|
||||
<h3 id="tool">Creating and running a ClangTool.</h3>
|
||||
<p>Once we have a CompilationDatabase, we can create a ClangTool and run our
|
||||
FrontendAction over some code. For example, to run the SyntaxOnlyAction over
|
||||
the files "a.cc" and "b.cc" one would write:
|
||||
<p>Once we have a <code>CompilationDatabase</code>, we can create a
|
||||
<code>ClangTool</code> and run our <code>FrontendAction</code> over some code.
|
||||
For example, to run the <code>SyntaxOnlyAction</code> over the files "a.cc" and
|
||||
"b.cc" one would write:
|
||||
<pre>
|
||||
// A clang tool can run over a number of sources in the same process...
|
||||
std::vector<std::string> Sources;
|
||||
@ -103,7 +97,7 @@ the files "a.cc" and "b.cc" one would write:
|
||||
|
||||
// We hand the CompilationDatabase we created and the sources to run over into
|
||||
// the tool constructor.
|
||||
ClangTool Tool(*Compilations, Sources);
|
||||
ClangTool Tool(OptionsParser.GetCompilations(), Sources);
|
||||
|
||||
// The ClangTool needs a new FrontendAction for each translation unit we run
|
||||
// on. Thus, it takes a FrontendActionFactory as parameter. To create a
|
||||
@ -117,40 +111,29 @@ the files "a.cc" and "b.cc" one would write:
|
||||
<p>Now we combine the two previous steps into our first real tool. This example
|
||||
tool is also checked into the clang tree at tools/clang-check/ClangCheck.cpp.
|
||||
<pre>
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
// Declares clang::SyntaxOnlyAction.
|
||||
#include "clang/Frontend/FrontendActions.h"
|
||||
#include "clang/Tooling/CompilationDatabase.h"
|
||||
#include "clang/Tooling/CommonOptionsParser.h"
|
||||
#include "clang/Tooling/Tooling.h"
|
||||
// Declares llvm::cl::extrahelp.
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
|
||||
using namespace clang::tooling;
|
||||
using namespace llvm;
|
||||
|
||||
cl::opt<std::string> BuildPath(
|
||||
"p",
|
||||
cl::desc("<build-path>"),
|
||||
cl::Optional);
|
||||
// CommonOptionsParser declares HelpMessage with a description of the common
|
||||
// command-line options related to the compilation database and input files.
|
||||
// It's nice to have this help message in all tools.
|
||||
static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage);
|
||||
|
||||
cl::list<std::string> SourcePaths(
|
||||
cl::Positional,
|
||||
cl::desc("<source0> [... <sourceN>]"),
|
||||
cl::OneOrMore);
|
||||
// A help message for this specific tool can be added afterwards.
|
||||
static cl::extrahelp MoreHelp("\nMore help text...");
|
||||
|
||||
int main(int argc, const char **argv) {
|
||||
llvm::OwningPtr<CompilationDatabase> Compilations(
|
||||
FixedCompilationDatabase::loadFromCommandLine(argc, argv));
|
||||
cl::ParseCommandLineOptions(argc, argv);
|
||||
if (!Compilations) {
|
||||
std::string ErrorMessage;
|
||||
Compilations.reset(
|
||||
!BuildPath.empty() ?
|
||||
CompilationDatabase::autoDetectFromDirectory(BuildPath, ErrorMessage) :
|
||||
CompilationDatabase::autoDetectFromSource(SourcePaths[0], ErrorMessage)
|
||||
);
|
||||
if (!Compilations)
|
||||
llvm::report_fatal_error(ErrorMessage);
|
||||
}
|
||||
ClangTool Tool(*Compilations, SourcePaths);
|
||||
return Tool.run(newFrontendActionFactory<clang::SyntaxOnlyAction>());
|
||||
CommonOptionsParser OptionsParser(argc, argv);
|
||||
ClangTool Tool(OptionsParser.GetCompilations(),
|
||||
OptionsParser.GetSourcePathList());
|
||||
return Tool.run(newFrontendActionFactory<clang::SyntaxOnlyAction>());
|
||||
}
|
||||
</pre>
|
||||
</p>
|
||||
|
@ -178,7 +178,7 @@ A C string literal prefixed by the <code>'@'</code> token denotes an <code>NSStr
|
||||
<pre>
|
||||
// Partition command line arguments into positional and option arguments.
|
||||
NSMutableArray *args = [NSMutableArray new];
|
||||
NSMutableDictionary *options = [NSMutableArray new];
|
||||
NSMutableDictionary *options = [NSMutableDictionary new];
|
||||
while (--argc) {
|
||||
const char *arg = *++argv;
|
||||
if (strncmp(arg, "--", 2) == 0) {
|
||||
|
@ -2,7 +2,7 @@
|
||||
"http://www.w3.org/TR/html4/strict.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Precompiled Headers (PCH)</title>
|
||||
<title>Precompiled Header and Modules Internals</title>
|
||||
<link type="text/css" rel="stylesheet" href="../menu.css">
|
||||
<link type="text/css" rel="stylesheet" href="../content.css">
|
||||
<style type="text/css">
|
||||
@ -18,10 +18,10 @@
|
||||
|
||||
<div id="content">
|
||||
|
||||
<h1>Precompiled Headers</h1>
|
||||
<h1>Precompiled Header and Modules Internals</h1>
|
||||
|
||||
<p>This document describes the design and implementation of Clang's
|
||||
precompiled headers (PCH). If you are interested in the end-user
|
||||
precompiled headers (PCH) and modules. If you are interested in the end-user
|
||||
view, please see the <a
|
||||
href="UsersManual.html#precompiledheaders">User's Manual</a>.</p>
|
||||
|
||||
@ -30,7 +30,7 @@
|
||||
<li><a href="#usage">Using Precompiled Headers with
|
||||
<tt>clang</tt></a></li>
|
||||
<li><a href="#philosophy">Design Philosophy</a></li>
|
||||
<li><a href="#contents">Precompiled Header Contents</a>
|
||||
<li><a href="#contents">Serialized AST File Contents</a>
|
||||
<ul>
|
||||
<li><a href="#metadata">Metadata Block</a></li>
|
||||
<li><a href="#sourcemgr">Source Manager Block</a></li>
|
||||
@ -42,8 +42,9 @@
|
||||
<li><a href="#method-pool">Method Pool Block</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#tendrils">Precompiled Header Integration
|
||||
Points</a></li>
|
||||
<li><a href="#tendrils">AST Reader Integration Points</a></li>
|
||||
<li><a href="#chained">Chained precompiled headers</a></li>
|
||||
<li><a href="#modules">Modules</a></li>
|
||||
</ul>
|
||||
|
||||
<h2 id="usage">Using Precompiled Headers with <tt>clang</tt></h2>
|
||||
@ -94,30 +95,39 @@ with the <b><tt>-include-pch</tt></b> option:</p>
|
||||
require the PCH file to be up-to-date.</li>
|
||||
</ul>
|
||||
|
||||
<p>Clang's precompiled headers are designed with a compact on-disk
|
||||
representation, which minimizes both PCH creation time and the time
|
||||
required to initially load the PCH file. The PCH file itself contains
|
||||
<p>Modules, as implemented in Clang, use the same mechanisms as
|
||||
precompiled headers to save a serialized AST file (one per module) and
|
||||
use those AST modules. From an implementation standpoint, modules are
|
||||
a generalization of precompiled headers, lifting a number of
|
||||
restrictions placed on precompiled headers. In particular, there can
|
||||
only be one precompiled header and it must be included at the
|
||||
beginning of the translation unit. The extensions to the AST file
|
||||
format required for modules are discussed in the section on <a href="#modules">modules</a>.</p>
|
||||
|
||||
<p>Clang's AST files are designed with a compact on-disk
|
||||
representation, which minimizes both creation time and the time
|
||||
required to initially load the AST file. The AST file itself contains
|
||||
a serialized representation of Clang's abstract syntax trees and
|
||||
supporting data structures, stored using the same compressed bitstream
|
||||
as <a href="http://llvm.org/docs/BitCodeFormat.html">LLVM's bitcode
|
||||
file format</a>.</p>
|
||||
|
||||
<p>Clang's precompiled headers are loaded "lazily" from disk. When a
|
||||
PCH file is initially loaded, Clang reads only a small amount of data
|
||||
from the PCH file to establish where certain important data structures
|
||||
<p>Clang's AST files are loaded "lazily" from disk. When an
|
||||
AST file is initially loaded, Clang reads only a small amount of data
|
||||
from the AST file to establish where certain important data structures
|
||||
are stored. The amount of data read in this initial load is
|
||||
independent of the size of the PCH file, such that a larger PCH file
|
||||
does not lead to longer PCH load times. The actual header data in the
|
||||
PCH file--macros, functions, variables, types, etc.--is loaded only
|
||||
independent of the size of the AST file, such that a larger AST file
|
||||
does not lead to longer AST load times. The actual header data in the
|
||||
AST file--macros, functions, variables, types, etc.--is loaded only
|
||||
when it is referenced from the user's code, at which point only that
|
||||
entity (and those entities it depends on) are deserialized from the
|
||||
PCH file. With this approach, the cost of using a precompiled header
|
||||
AST file. With this approach, the cost of using an AST file
|
||||
for a translation unit is proportional to the amount of code actually
|
||||
used from the header, rather than being proportional to the size of
|
||||
the header itself.</p>
|
||||
used from the AST file, rather than being proportional to the size of
|
||||
the AST file itself.</p>
|
||||
|
||||
<p>When given the <code>-print-stats</code> option, Clang produces
|
||||
statistics describing how much of the precompiled header was actually
|
||||
statistics describing how much of the AST file was actually
|
||||
loaded from disk. For a simple "Hello, World!" program that includes
|
||||
the Apple <code>Cocoa.h</code> header (which is built as a precompiled
|
||||
header), this option illustrates how little of the actual precompiled
|
||||
@ -143,7 +153,7 @@ header is required:</p>
|
||||
<p>For this small program, only a tiny fraction of the source
|
||||
locations, types, declarations, identifiers, and macros were actually
|
||||
deserialized from the precompiled header. These statistics can be
|
||||
useful to determine whether the precompiled header implementation can
|
||||
useful to determine whether the AST file implementation can
|
||||
be improved by making more of the implementation lazy.</p>
|
||||
|
||||
<p>Precompiled headers can be chained. When you create a PCH while
|
||||
@ -153,13 +163,15 @@ example, you could create a PCH out of all the headers that are very
|
||||
commonly used throughout your project, and then create a PCH for every
|
||||
single source file in the project that includes the code that is
|
||||
specific to that file, so that recompiling the file itself is very fast,
|
||||
without duplicating the data from the common headers for every file.</p>
|
||||
without duplicating the data from the common headers for every
|
||||
file. The mechanisms behind chained precompiled headers are discussed
|
||||
in a <a href="#chained">later section</a>.
|
||||
|
||||
<h2 id="contents">Precompiled Header Contents</h2>
|
||||
<h2 id="contents">AST File Contents</h2>
|
||||
|
||||
<img src="PCHLayout.png" style="float:right" alt="Precompiled header layout">
|
||||
|
||||
<p>Clang's precompiled headers are organized into several different
|
||||
<p>Clang's AST files are organized into several different
|
||||
blocks, each of which contains the serialized representation of a part
|
||||
of Clang's internal representation. Each of the blocks corresponds to
|
||||
either a block or a record within <a
|
||||
@ -167,19 +179,19 @@ either a block or a record within <a
|
||||
format</a>. The contents of each of these logical blocks are described
|
||||
below.</p>
|
||||
|
||||
<p>For a given precompiled header, the <a
|
||||
<p>For a given AST file, the <a
|
||||
href="http://llvm.org/cmds/llvm-bcanalyzer.html"><code>llvm-bcanalyzer</code></a>
|
||||
utility can be used to examine the actual structure of the bitstream
|
||||
for the precompiled header. This information can be used both to help
|
||||
understand the structure of the precompiled header and to isolate
|
||||
areas where precompiled headers can still be optimized, e.g., through
|
||||
for the AST file. This information can be used both to help
|
||||
understand the structure of the AST file and to isolate
|
||||
areas where AST files can still be optimized, e.g., through
|
||||
the introduction of abbreviations.</p>
|
||||
|
||||
<h3 id="metadata">Metadata Block</h3>
|
||||
|
||||
<p>The metadata block contains several records that provide
|
||||
information about how the precompiled header was built. This metadata
|
||||
is primarily used to validate the use of a precompiled header. For
|
||||
information about how the AST file was built. This metadata
|
||||
is primarily used to validate the use of an AST file. For
|
||||
example, a precompiled header built for a 32-bit x86 target cannot be used
|
||||
when compiling for a 64-bit x86 target. The metadata block contains
|
||||
information about:</p>
|
||||
@ -187,17 +199,17 @@ information about:</p>
|
||||
<dl>
|
||||
<dt>Language options</dt>
|
||||
<dd>Describes the particular language dialect used to compile the
|
||||
PCH file, including major options (e.g., Objective-C support) and more
|
||||
AST file, including major options (e.g., Objective-C support) and more
|
||||
minor options (e.g., support for "//" comments). The contents of this
|
||||
record correspond to the <code>LangOptions</code> class.</dd>
|
||||
|
||||
<dt>Target architecture</dt>
|
||||
<dd>The target triple that describes the architecture, platform, and
|
||||
ABI for which the PCH file was generated, e.g.,
|
||||
ABI for which the AST file was generated, e.g.,
|
||||
<code>i386-apple-darwin9</code>.</dd>
|
||||
|
||||
<dt>PCH version</dt>
|
||||
<dd>The major and minor version numbers of the precompiled header
|
||||
<dt>AST version</dt>
|
||||
<dd>The major and minor version numbers of the AST file
|
||||
format. Changes in the minor version number should not affect backward
|
||||
compatibility, while changes in the major version number imply that a
|
||||
newer compiler cannot read an older precompiled header (and
|
||||
@ -205,11 +217,11 @@ vice-versa).</dd>
|
||||
|
||||
<dt>Original file name</dt>
|
||||
<dd>The full path of the header that was used to generate the
|
||||
precompiled header.</dd>
|
||||
AST file.</dd>
|
||||
|
||||
<dt>Predefines buffer</dt>
|
||||
<dd>Although not explicitly stored as part of the metadata, the
|
||||
predefines buffer is used in the validation of the precompiled header.
|
||||
predefines buffer is used in the validation of the AST file.
|
||||
The predefines buffer itself contains code generated by the compiler
|
||||
to initialize the preprocessor state according to the current target,
|
||||
platform, and command-line options. For example, the predefines buffer
|
||||
@ -220,26 +232,14 @@ contents are verified along with the rest of the metadata.</dd>
|
||||
|
||||
</dl>
|
||||
|
||||
<p>A chained PCH file (that is, one that references another PCH) has
|
||||
a slightly different metadata block, which contains the following
|
||||
information:</p>
|
||||
<p>A chained PCH file (that is, one that references another PCH) and a
|
||||
module (which may import other modules) have additional metadata
|
||||
containing the list of all AST files that this AST file depends
|
||||
on. Each of those files will be loaded along with this AST file.</p>
|
||||
|
||||
<dl>
|
||||
<dt>Referenced file</dt>
|
||||
<dd>The name of the referenced PCH file. It is looked up like a file
|
||||
specified using -include-pch.</dd>
|
||||
|
||||
<dt>PCH version</dt>
|
||||
<dd>This is the same as in normal PCH files.</dd>
|
||||
|
||||
<dt>Original file name</dt>
|
||||
<dd>The full path of the header that was used to generate this
|
||||
precompiled header.</dd>
|
||||
|
||||
</dl>
|
||||
|
||||
<p>The language options, target architecture and predefines buffer data
|
||||
is taken from the end of the chain, since they have to match anyway.</p>
|
||||
<p>For chained precompiled headers, the language options, target
|
||||
architecture and predefines buffer data is taken from the end of the
|
||||
chain, since they have to match anyway.</p>
|
||||
|
||||
<h3 id="sourcemgr">Source Manager Block</h3>
|
||||
|
||||
@ -248,10 +248,10 @@ Clang's <a
|
||||
href="InternalsManual.html#SourceLocation">SourceManager</a> class,
|
||||
which handles the mapping from source locations (as represented in
|
||||
Clang's abstract syntax tree) into actual column/line positions within
|
||||
a source file or macro instantiation. The precompiled header's
|
||||
a source file or macro instantiation. The AST file's
|
||||
representation of the source manager also includes information about
|
||||
all of the headers that were (transitively) included when building the
|
||||
precompiled header.</p>
|
||||
AST file.</p>
|
||||
|
||||
<p>The bulk of the source manager block is dedicated to information
|
||||
about the various files, buffers, and macro instantiations into which
|
||||
@ -259,18 +259,18 @@ a source location can refer. Each of these is referenced by a numeric
|
||||
"file ID", which is a unique number (allocated starting at 1) stored
|
||||
in the source location. Clang serializes the information for each kind
|
||||
of file ID, along with an index that maps file IDs to the position
|
||||
within the PCH file where the information about that file ID is
|
||||
within the AST file where the information about that file ID is
|
||||
stored. The data associated with a file ID is loaded only when
|
||||
required by the front end, e.g., to emit a diagnostic that includes a
|
||||
macro instantiation history inside the header itself.</p>
|
||||
|
||||
<p>The source manager block also contains information about all of the
|
||||
headers that were included when building the precompiled header. This
|
||||
headers that were included when building the AST file. This
|
||||
includes information about the controlling macro for the header (e.g.,
|
||||
when the preprocessor identified that the contents of the header
|
||||
dependent on a macro like <code>LLVM_CLANG_SOURCEMANAGER_H</code>)
|
||||
along with a cached version of the results of the <code>stat()</code>
|
||||
system calls performed when building the precompiled header. The
|
||||
system calls performed when building the AST file. The
|
||||
latter is particularly useful in reducing system time when searching
|
||||
for include files.</p>
|
||||
|
||||
@ -279,8 +279,8 @@ for include files.</p>
|
||||
<p>The preprocessor block contains the serialized representation of
|
||||
the preprocessor. Specifically, it contains all of the macros that
|
||||
have been defined by the end of the header used to build the
|
||||
precompiled header, along with the token sequences that comprise each
|
||||
macro. The macro definitions are only read from the PCH file when the
|
||||
AST file, along with the token sequences that comprise each
|
||||
macro. The macro definitions are only read from the AST file when the
|
||||
name of the macro first occurs in the program. This lazy loading of
|
||||
macro definitions is triggered by lookups into the <a
|
||||
href="#idtable">identifier table</a>.</p>
|
||||
@ -290,8 +290,8 @@ macro definitions is triggered by lookups into the <a
|
||||
<p>The types block contains the serialized representation of all of
|
||||
the types referenced in the translation unit. Each Clang type node
|
||||
(<code>PointerType</code>, <code>FunctionProtoType</code>, etc.) has a
|
||||
corresponding record type in the PCH file. When types are deserialized
|
||||
from the precompiled header, the data within the record is used to
|
||||
corresponding record type in the AST file. When types are deserialized
|
||||
from the AST file, the data within the record is used to
|
||||
reconstruct the appropriate type node using the AST context.</p>
|
||||
|
||||
<p>Each type has a unique type ID, which is an integer that uniquely
|
||||
@ -300,10 +300,10 @@ less than <code>NUM_PREDEF_TYPE_IDS</code> represent predefined types
|
||||
(<code>void</code>, <code>float</code>, etc.), while other
|
||||
"user-defined" type IDs are assigned consecutively from
|
||||
<code>NUM_PREDEF_TYPE_IDS</code> upward as the types are encountered.
|
||||
The PCH file has an associated mapping from the user-defined types
|
||||
The AST file has an associated mapping from the user-defined types
|
||||
block to the location within the types block where the serialized
|
||||
representation of that type resides, enabling lazy deserialization of
|
||||
types. When a type is referenced from within the PCH file, that
|
||||
types. When a type is referenced from within the AST file, that
|
||||
reference is encoded using the type ID shifted left by 3 bits. The
|
||||
lower three bits are used to represent the <code>const</code>,
|
||||
<code>volatile</code>, and <code>restrict</code> qualifiers, as in
|
||||
@ -316,19 +316,20 @@ class.</p>
|
||||
<p>The declarations block contains the serialized representation of
|
||||
all of the declarations referenced in the translation unit. Each Clang
|
||||
declaration node (<code>VarDecl</code>, <code>FunctionDecl</code>,
|
||||
etc.) has a corresponding record type in the PCH file. When
|
||||
declarations are deserialized from the precompiled header, the data
|
||||
etc.) has a corresponding record type in the AST file. When
|
||||
declarations are deserialized from the AST file, the data
|
||||
within the record is used to build and populate a new instance of the
|
||||
corresponding <code>Decl</code> node. As with types, each declaration
|
||||
node has a numeric ID that is used to refer to that declaration within
|
||||
the PCH file. In addition, a lookup table provides a mapping from that
|
||||
the AST file. In addition, a lookup table provides a mapping from that
|
||||
numeric ID to the offset within the precompiled header where that
|
||||
declaration is described.</p>
|
||||
|
||||
<p>Declarations in Clang's abstract syntax trees are stored
|
||||
hierarchically. At the top of the hierarchy is the translation unit
|
||||
(<code>TranslationUnitDecl</code>), which contains all of the
|
||||
declarations in the translation unit. These declarations (such as
|
||||
declarations in the translation unit but is not actually written as a
|
||||
specific declaration node. Its child declarations (such as
|
||||
functions or struct types) may also contain other declarations inside
|
||||
them, and so on. Within Clang, each declaration is stored within a <a
|
||||
href="http://clang.llvm.org/docs/InternalsManual.html#DeclContext">declaration
|
||||
@ -339,7 +340,7 @@ in a structure) and iterate over the declarations stored within a
|
||||
context (e.g., iterate over all of the fields of a structure for
|
||||
structure layout).</p>
|
||||
|
||||
<p>In Clang's precompiled header format, deserializing a declaration
|
||||
<p>In Clang's AST file format, deserializing a declaration
|
||||
that is a <code>DeclContext</code> is a separate operation from
|
||||
deserializing all of the declarations stored within that declaration
|
||||
context. Therefore, Clang will deserialize the translation unit
|
||||
@ -354,14 +355,11 @@ the name-lookup and iteration behavior described above:</p>
|
||||
<code>x</code> within a given declaration context (for example,
|
||||
during semantic analysis of the expression <code>p->x</code>,
|
||||
where <code>p</code>'s type is defined in the precompiled header),
|
||||
Clang deserializes a hash table mapping from the names within that
|
||||
declaration context to the declaration IDs that represent each
|
||||
visible declaration with that name. The entire hash table is
|
||||
deserialized at this point (into the <code>llvm::DenseMap</code>
|
||||
stored within each <code>DeclContext</code> object), but the actual
|
||||
declarations are not yet deserialized. In a second step, those
|
||||
declarations with the name <code>x</code> will be deserialized and
|
||||
will be used as the result of name lookup.</li>
|
||||
Clang refers to an on-disk hash table that maps from the names
|
||||
within that declaration context to the declaration IDs that
|
||||
represent each visible declaration with that name. The actual
|
||||
declarations will then be deserialized to provide the results of
|
||||
name lookup.</li>
|
||||
|
||||
<li>When the front end performs iteration over all of the
|
||||
declarations within a declaration context, all of those declarations
|
||||
@ -376,7 +374,7 @@ the name-lookup and iteration behavior described above:</p>
|
||||
|
||||
<h3 id="stmt">Statements and Expressions</h3>
|
||||
|
||||
<p>Statements and expressions are stored in the precompiled header in
|
||||
<p>Statements and expressions are stored in the AST file in
|
||||
both the <a href="#types">types</a> and the <a
|
||||
href="#decls">declarations</a> blocks, because every statement or
|
||||
expression will be associated with either a type or declaration. The
|
||||
@ -389,10 +387,10 @@ function.</p>
|
||||
<p>As with types and declarations, each statement and expression kind
|
||||
in Clang's abstract syntax tree (<code>ForStmt</code>,
|
||||
<code>CallExpr</code>, etc.) has a corresponding record type in the
|
||||
precompiled header, which contains the serialized representation of
|
||||
AST file, which contains the serialized representation of
|
||||
that statement or expression. Each substatement or subexpression
|
||||
within an expression is stored as a separate record (which keeps most
|
||||
records to a fixed size). Within the precompiled header, the
|
||||
records to a fixed size). Within the AST file, the
|
||||
subexpressions of an expression are stored, in reverse order, prior to the expression
|
||||
that owns those expression, using a form of <a
|
||||
href="http://en.wikipedia.org/wiki/Reverse_Polish_notation">Reverse
|
||||
@ -420,7 +418,7 @@ they are part of a different expression.</p>
|
||||
<h3 id="idtable">Identifier Table Block</h3>
|
||||
|
||||
<p>The identifier table block contains an on-disk hash table that maps
|
||||
each identifier mentioned within the precompiled header to the
|
||||
each identifier mentioned within the AST file to the
|
||||
serialized representation of the identifier's information (e.g, the
|
||||
<code>IdentifierInfo</code> structure). The serialized representation
|
||||
contains:</p>
|
||||
@ -438,17 +436,20 @@ contains:</p>
|
||||
declarations.</li>
|
||||
</ul>
|
||||
|
||||
<p>When a precompiled header is loaded, the precompiled header
|
||||
<p>When an AST file is loaded, the AST file reader
|
||||
mechanism introduces itself into the identifier table as an external
|
||||
lookup source. Thus, when the user program refers to an identifier
|
||||
that has not yet been seen, Clang will perform a lookup into the
|
||||
identifier table. If an identifier is found, its contents (macro
|
||||
definitions, flags, top-level declarations, etc.) will be deserialized, at which point the corresponding <code>IdentifierInfo</code> structure will have the same contents it would have after parsing the headers in the precompiled header.</p>
|
||||
definitions, flags, top-level declarations, etc.) will be
|
||||
deserialized, at which point the corresponding
|
||||
<code>IdentifierInfo</code> structure will have the same contents it
|
||||
would have after parsing the headers in the AST file.</p>
|
||||
|
||||
<p>Within the PCH file, the identifiers used to name declarations are represented with an integral value. A separate table provides a mapping from this integral value (the identifier ID) to the location within the on-disk
|
||||
<p>Within the AST file, the identifiers used to name declarations are represented with an integral value. A separate table provides a mapping from this integral value (the identifier ID) to the location within the on-disk
|
||||
hash table where that identifier is stored. This mapping is used when
|
||||
deserializing the name of a declaration, the identifier of a token, or
|
||||
any other construct in the PCH file that refers to a name.</p>
|
||||
any other construct in the AST file that refers to a name.</p>
|
||||
|
||||
<h3 id="method-pool">Method Pool Block</h3>
|
||||
|
||||
@ -457,7 +458,7 @@ serves two purposes: it provides a mapping from the names of
|
||||
Objective-C selectors to the set of Objective-C instance and class
|
||||
methods that have that particular selector (which is required for
|
||||
semantic analysis in Objective-C) and also stores all of the selectors
|
||||
used by entities within the precompiled header. The design of the
|
||||
used by entities within the AST file. The design of the
|
||||
method pool is similar to that of the <a href="#idtable">identifier
|
||||
table</a>: the first time a particular selector is formed during the
|
||||
compilation of the program, Clang will search in the on-disk hash
|
||||
@ -468,25 +469,25 @@ structure (<code>Sema::InstanceMethodPool</code> and
|
||||
respectively).</p>
|
||||
|
||||
<p>As with identifiers, selectors are represented by numeric values
|
||||
within the PCH file. A separate index maps these numeric selector
|
||||
within the AST file. A separate index maps these numeric selector
|
||||
values to the offset of the selector within the on-disk hash table,
|
||||
and will be used when de-serializing an Objective-C method declaration
|
||||
(or other Objective-C construct) that refers to the selector.</p>
|
||||
|
||||
<h2 id="tendrils">Precompiled Header Integration Points</h2>
|
||||
<h2 id="tendrils">AST Reader Integration Points</h2>
|
||||
|
||||
<p>The "lazy" deserialization behavior of precompiled headers requires
|
||||
<p>The "lazy" deserialization behavior of AST files requires
|
||||
their integration into several completely different submodules of
|
||||
Clang. For example, lazily deserializing the declarations during name
|
||||
lookup requires that the name-lookup routines be able to query the
|
||||
precompiled header to find entities within the PCH file.</p>
|
||||
AST file to find entities stored there.</p>
|
||||
|
||||
<p>For each Clang data structure that requires direct interaction with
|
||||
the precompiled header logic, there is an abstract class that provides
|
||||
the interface between the two modules. The <code>PCHReader</code>
|
||||
class, which handles the loading of a precompiled header, inherits
|
||||
the AST reader logic, there is an abstract class that provides
|
||||
the interface between the two modules. The <code>ASTReader</code>
|
||||
class, which handles the loading of an AST file, inherits
|
||||
from all of these abstract classes to provide lazy deserialization of
|
||||
Clang's data structures. <code>PCHReader</code> implements the
|
||||
Clang's data structures. <code>ASTReader</code> implements the
|
||||
following abstract classes:</p>
|
||||
|
||||
<dl>
|
||||
@ -505,7 +506,7 @@ following abstract classes:</p>
|
||||
<dd>This abstract interface is associated with the
|
||||
<code>IdentifierTable</code> class, and is used whenever the
|
||||
program source refers to an identifier that has not yet been seen.
|
||||
In this case, the precompiled header implementation searches for
|
||||
In this case, the AST reader searches for
|
||||
this identifier within its <a href="#idtable">identifier table</a>
|
||||
to load any top-level declarations or macros associated with that
|
||||
identifier.</dd>
|
||||
@ -513,7 +514,7 @@ following abstract classes:</p>
|
||||
<dt><code>ExternalASTSource</code></dt>
|
||||
<dd>This abstract interface is associated with the
|
||||
<code>ASTContext</code> class, and is used whenever the abstract
|
||||
syntax tree nodes need to loaded from the precompiled header. It
|
||||
syntax tree nodes need to loaded from the AST file. It
|
||||
provides the ability to de-serialize declarations and types
|
||||
identified by their numeric values, read the bodies of functions
|
||||
when required, and read the declarations stored within a
|
||||
@ -526,6 +527,131 @@ following abstract classes:</p>
|
||||
pool</a>.</dd>
|
||||
</dl>
|
||||
|
||||
<h2 id="chained">Chained precompiled headers</h2>
|
||||
|
||||
<p>Chained precompiled headers were initially intended to improve the
|
||||
performance of IDE-centric operations such as syntax highlighting and
|
||||
code completion while a particular source file is being edited by the
|
||||
user. To minimize the amount of reparsing required after a change to
|
||||
the file, a form of precompiled header--called a precompiled
|
||||
<i>preamble</i>--is automatically generated by parsing all of the
|
||||
headers in the source file, up to and including the last
|
||||
#include. When only the source file changes (and none of the headers
|
||||
it depends on), reparsing of that source file can use the precompiled
|
||||
preamble and start parsing after the #includes, so parsing time is
|
||||
proportional to the size of the source file (rather than all of its
|
||||
includes). However, the compilation of that translation unit
|
||||
may already use a precompiled header: in this case, Clang will create
|
||||
the precompiled preamble as a chained precompiled header that refers
|
||||
to the original precompiled header. This drastically reduces the time
|
||||
needed to serialize the precompiled preamble for use in reparsing.</p>
|
||||
|
||||
<p>Chained precompiled headers get their name because each precompiled header
|
||||
can depend on one other precompiled header, forming a chain of
|
||||
dependencies. A translation unit will then include the precompiled
|
||||
header that starts the chain (i.e., nothing depends on it). This
|
||||
linearity of dependencies is important for the semantic model of
|
||||
chained precompiled headers, because the most-recent precompiled
|
||||
header can provide information that overrides the information provided
|
||||
by the precompiled headers it depends on, just like a header file
|
||||
<code>B.h</code> that includes another header <code>A.h</code> can
|
||||
modify the state produced by parsing <code>A.h</code>, e.g., by
|
||||
<code>#undef</code>'ing a macro defined in <code>A.h</code>.</p>
|
||||
|
||||
<p>There are several ways in which chained precompiled headers
|
||||
generalize the AST file model:</p>
|
||||
|
||||
<dl>
|
||||
<dt>Numbering of IDs</dt>
|
||||
<dd>Many different kinds of entities--identifiers, declarations,
|
||||
types, etc.---have ID numbers that start at 1 or some other
|
||||
predefined constant and grow upward. Each precompiled header records
|
||||
the maximum ID number it has assigned in each category. Then, when a
|
||||
new precompiled header is generated that depends on (chains to)
|
||||
another precompiled header, it will start counting at the next
|
||||
available ID number. This way, one can determine, given an ID
|
||||
number, which AST file actually contains the entity.</dd>
|
||||
|
||||
<dt>Name lookup</dt>
|
||||
<dd>When writing a chained precompiled header, Clang attempts to
|
||||
write only information that has changed from the precompiled header
|
||||
on which it is based. This changes the lookup algorithm for the
|
||||
various tables, such as the <a href="#idtable">identifier table</a>:
|
||||
the search starts at the most-recent precompiled header. If no entry
|
||||
is found, lookup then proceeds to the identifier table in the
|
||||
precompiled header it depends on, and so one. Once a lookup
|
||||
succeeds, that result is considered definitive, overriding any
|
||||
results from earlier precompiled headers.</dd>
|
||||
|
||||
<dt>Update records</dt>
|
||||
<dd>There are various ways in which a later precompiled header can
|
||||
modify the entities described in an earlier precompiled header. For
|
||||
example, later precompiled headers can add entries into the various
|
||||
name-lookup tables for the translation unit or namespaces, or add
|
||||
new categories to an Objective-C class. Each of these updates is
|
||||
captured in an "update record" that is stored in the chained
|
||||
precompiled header file and will be loaded along with the original
|
||||
entity.</dd>
|
||||
</dl>
|
||||
|
||||
<h2 id="modules">Modules</h2>
|
||||
|
||||
<p>Modules generalize the chained precompiled header model yet
|
||||
further, from a linear chain of precompiled headers to an arbitrary
|
||||
directed acyclic graph (DAG) of AST files. All of the same techniques
|
||||
used to make chained precompiled headers work---ID number, name
|
||||
lookup, update records---are shared with modules. However, the DAG
|
||||
nature of modules introduce a number of additional complications to
|
||||
the model:
|
||||
|
||||
<dl>
|
||||
<dt>Numbering of IDs</dt>
|
||||
<dd>The simple, linear numbering scheme used in chained precompiled
|
||||
headers falls apart with the module DAG, because different modules
|
||||
may end up with different numbering schemes for entities they
|
||||
imported from common shared modules. To account for this, each
|
||||
module file provides information about which modules it depends on
|
||||
and which ID numbers it assigned to the entities in those modules,
|
||||
as well as which ID numbers it took for its own new entities. The
|
||||
AST reader then maps these "local" ID numbers into a "global" ID
|
||||
number space for the current translation unit, providing a 1-1
|
||||
mapping between entities (in whatever AST file they inhabit) and
|
||||
global ID numbers. If that translation unit is then serialized into
|
||||
an AST file, this mapping will be stored for use when the AST file
|
||||
is imported.</dd>
|
||||
|
||||
<dt>Declaration merging</dt>
|
||||
<dd>It is possible for a given entity (from the language's
|
||||
perspective) to be declared multiple times in different places. For
|
||||
example, two different headers can have the declaration of
|
||||
<tt>printf</tt> or could forward-declare <tt>struct stat</tt>. If
|
||||
each of those headers is included in a module, and some third party
|
||||
imports both of those modules, there is a potentially serious
|
||||
problem: name lookup for <tt>printf</tt> or <tt>struct stat</tt> will
|
||||
find both declarations, but the AST nodes are unrelated. This would
|
||||
result in a compilation error, due to an ambiguity in name
|
||||
lookup. Therefore, the AST reader performs declaration merging
|
||||
according to the appropriate language semantics, ensuring that the
|
||||
two disjoint declarations are merged into a single redeclaration
|
||||
chain (with a common canonical declaration), so that it is as if one
|
||||
of the headers had been included before the other.</dd>
|
||||
|
||||
<dt>Name Visibility</dt>
|
||||
<dd>Modules allow certain names that occur during module creation to
|
||||
be "hidden", so that they are not part of the public interface of
|
||||
the module and are not visible to its clients. The AST reader
|
||||
maintains a "visible" bit on various AST nodes (declarations, macros,
|
||||
etc.) to indicate whether that particular AST node is currently
|
||||
visible; the various name lookup mechanisms in Clang inspect the
|
||||
visible bit to determine whether that entity, which is still in the
|
||||
AST (because other, visible AST nodes may depend on it), can
|
||||
actually be found by name lookup. When a new (sub)module is
|
||||
imported, it may make existing, non-visible, already-deserialized
|
||||
AST nodes visible; it is the responsibility of the AST reader to
|
||||
find and update these AST nodes when it is notified of the import.</dd>
|
||||
|
||||
</dl>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
|
@ -170,6 +170,16 @@ int f(vector<map<int, double>>);
|
||||
|
||||
</li>
|
||||
|
||||
<li>Clang's <tt>-fcatch-undefined-behavior</tt> option has been renamed to
|
||||
<tt>-fsanitize=undefined</tt> and has grown the ability to check for several
|
||||
new types of undefined behavior. See the Users Manual for more information.
|
||||
|
||||
<!-- Flesh this out prior to release. -->
|
||||
|
||||
<!-- Document renaming of -faddress-sanitizer and -fthread-sanitizer. -->
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
<h4 id="tlsmodel">Support for <code>tls_model</code> attribute</h4>
|
||||
|
@ -37,9 +37,8 @@ Typical slowdown introduced by ThreadSanitizer is <b>5x-15x</b> (TODO: these num
|
||||
approximate so far).
|
||||
|
||||
<h2 id="howtobuild">How to build</h2>
|
||||
Follow the <a href="../get_started.html">clang build instructions</a>. <BR>
|
||||
Note: CMake build does not work yet.
|
||||
See <a href="http://llvm.org/bugs/show_bug.cgi?id=12272">bug 12272</a>.
|
||||
Follow the <a href="../get_started.html">clang build instructions</a>.
|
||||
CMake build is supported.<BR>
|
||||
|
||||
<h2 id="platforms">Supported Platforms</h2>
|
||||
ThreadSanitizer is supported on Linux x86_64 (tested on Ubuntu 10.04). <BR>
|
||||
@ -49,8 +48,8 @@ Support for 32-bit platforms is problematic and not yet planned.
|
||||
|
||||
|
||||
<h2 id="usage">Usage</h2>
|
||||
Simply compile your program with <tt>-fthread-sanitizer -fPIE</tt> and link it
|
||||
with <tt>-fthread-sanitizer -pie</tt>.<BR>
|
||||
Simply compile your program with <tt>-fsanitize=thread -fPIE</tt> and link it
|
||||
with <tt>-fsanitize=thread -pie</tt>.<BR>
|
||||
To get a reasonable performance add <tt>-O1</tt> or higher. <BR>
|
||||
Use <tt>-g</tt> to get file names and line numbers in the warning messages. <BR>
|
||||
|
||||
@ -73,7 +72,7 @@ int main() {
|
||||
</pre>
|
||||
|
||||
<pre>
|
||||
% clang -fthread-sanitizer -g -O1 tiny_race.c -fPIE -pie
|
||||
% clang -fsanitize=thread -g -O1 tiny_race.c -fPIE -pie
|
||||
</pre>
|
||||
|
||||
If a bug is detected, the program will print an error message to stderr.
|
||||
@ -111,7 +110,9 @@ This means that tools like <tt>ulimit</tt> may not work as usually expected.
|
||||
ThreadSanitizer is in alpha stage.
|
||||
It is known to work on large C++ programs using pthreads, but we do not promise
|
||||
anything (yet). <BR>
|
||||
C++11 threading is not yet supported.
|
||||
C++11 threading is not yet supported. <BR>
|
||||
The test suite is integrated into CMake build and can be run with
|
||||
<tt>make check-tsan</tt> command. <BR>
|
||||
|
||||
We are actively working on enhancing the tool -- stay tuned.
|
||||
Any help, especially in the form of minimized standalone tests is more than welcome.
|
||||
|
@ -874,33 +874,77 @@ likely to affect PCH files that reference a large number of headers.</p>
|
||||
|
||||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
||||
<dl>
|
||||
<dt id="opt_fcatch-undefined-behavior"><b>-fcatch-undefined-behavior</b>: Turn
|
||||
on runtime code generation to check for undefined behavior.</dt>
|
||||
<dt id="opt_fsanitize"><b>-fsanitize=check1,check2</b>: Turn on runtime checks
|
||||
for various forms of undefined behavior.</dt>
|
||||
|
||||
<dd>This option controls whether Clang adds runtime checks for various forms of
|
||||
undefined behavior, and is disabled by default. If a check fails, a diagnostic
|
||||
message is produced at runtime explaining the problem. The main checks are:
|
||||
|
||||
<dd>This option, which defaults to off, controls whether or not Clang
|
||||
adds runtime checks for undefined runtime behavior. If a check fails,
|
||||
<tt>__builtin_trap()</tt> is used to indicate failure.
|
||||
The checks are:
|
||||
<ul>
|
||||
<li>Subscripting where the static type of one operand is a variable
|
||||
which is decayed from an array type and the other operand is
|
||||
greater than the size of the array or less than zero.</li>
|
||||
<li>Shift operators where the amount shifted is greater or equal to the
|
||||
promoted bit-width of the left-hand-side or less than zero.</li>
|
||||
<li>If control flow reaches __builtin_unreachable.
|
||||
<li>When llvm implements more __builtin_object_size support, reads and
|
||||
writes for objects that __builtin_object_size indicates we aren't
|
||||
accessing valid memory. Bit-fields and vectors are not yet checked.
|
||||
<li id="opt_fsanitize_address"><tt>-fsanitize=address</tt>:
|
||||
<a href="AddressSanitizer.html">AddressSanitizer</a>, a memory error
|
||||
detector.</li>
|
||||
<li id="opt_fsanitize_thread"><tt>-fsanitize=thread</tt>:
|
||||
<a href="ThreadSanitizer.html">ThreadSanitizer</a>, an <em>experimental</em>
|
||||
data race detector. Not ready for widespread use.</li>
|
||||
<li id="opt_fsanitize_undefined"><tt>-fsanitize=undefined</tt>:
|
||||
Enables all the checks listed below.</li>
|
||||
</ul>
|
||||
|
||||
The following more fine-grained checks are also available:
|
||||
|
||||
<ul>
|
||||
<li id="opt_fsanitize_alignment"><tt>-fsanitize=alignment</tt>:
|
||||
Use of a misaligned pointer or creation of a misaligned reference.</li>
|
||||
<li id="opt_fsanitize_divide-by-zero"><tt>-fsanitize=divide-by-zero</tt>:
|
||||
Division by zero.</li>
|
||||
<li id="opt_fsanitize_float-cast-overflow"><tt>-fsanitize=float-cast-overflow</tt>:
|
||||
Conversion to, from, or between floating-point types which would overflow
|
||||
the destination.</li>
|
||||
<li id="opt_fsanitize_null"><tt>-fsanitize=null</tt>:
|
||||
Use of a null pointer or creation of a null reference.</li>
|
||||
<li id="opt_fsanitize_object-size"><tt>-fsanitize=object-size</tt>:
|
||||
An attempt to use bytes which the optimizer can determine are not part of
|
||||
the object being accessed.
|
||||
The sizes of objects are determined using <tt>__builtin_object_size</tt>, and
|
||||
consequently may be able to detect more problems at higher optimization
|
||||
levels.</li>
|
||||
<li id="opt_fsanitize_return"><tt>-fsanitize=return</tt>:
|
||||
In C++, reaching the end of a value-returning function without returning a
|
||||
value.</li>
|
||||
<li id="opt_fsanitize_shift"><tt>-fsanitize=shift</tt>:
|
||||
Shift operators where the amount shifted is greater or equal to the
|
||||
promoted bit-width of the left hand side or less than zero, or where
|
||||
the left hand side is negative. For a signed left shift, also checks
|
||||
for signed overflow in C, and for unsigned overflow in C++.</li>
|
||||
<li id="opt_fsanitize_signed-integer-overflow"><tt>-fsanitize=signed-integer-overflow</tt>:
|
||||
Signed integer overflow, including all the checks added by <tt>-ftrapv</tt>,
|
||||
and checking for overflow in signed division (<tt>INT_MIN / -1</tt>).</li>
|
||||
<li id="opt_fsanitize_unreachable"><tt>-fsanitize=unreachable</tt>:
|
||||
If control flow reaches __builtin_unreachable.</li>
|
||||
<li id="opt_fsanitize_vla-bound"><tt>-fsanitize=vla-bound</tt>:
|
||||
A variable-length array whose bound does not evaluate to a positive value.</li>
|
||||
<li id="opt_fsanitize_vptr"><tt>-fsanitize=vptr</tt>:
|
||||
Use of an object whose vptr indicates that it is of the wrong dynamic type,
|
||||
or that its lifetime has not begun or has ended. Incompatible with
|
||||
<tt>-fno-rtti</tt>.</li>
|
||||
</ul>
|
||||
|
||||
The <tt>-fsanitize=</tt> argument must also be provided when linking, in order
|
||||
to link to the appropriate runtime library. It is not possible to combine the
|
||||
<tt>-fsanitize=address</tt> and <tt>-fsanitize=thread</tt> checkers in the same
|
||||
program.
|
||||
</dd>
|
||||
|
||||
<dt id="opt_faddress-sanitizer"><b>-f[no-]address-sanitizer</b>:
|
||||
Turn on <a href="AddressSanitizer.html">AddressSanitizer</a>,
|
||||
a memory error detector.
|
||||
Deprecated synonym for <a href="#opt_fsanitize_address"><tt>-f[no-]sanitize=address</tt></a>.
|
||||
|
||||
<dt id="opt_fthread-sanitizer"><b>-f[no-]thread-sanitizer</b>:
|
||||
Turn on ThreadSanitizer, an <em>experimental</em> data race detector.
|
||||
Not ready for widespread use.
|
||||
Deprecated synonym for <a href="#opt_fsanitize_address"><tt>-f[no-]sanitize=thread</tt></a>.
|
||||
|
||||
<dt id="opt_fcatch-undefined-behavior"><b>-fcatch-undefined-behavior</b>:
|
||||
Deprecated synonym for <a href="#opt_fsanitize_undefined"><tt>-fsanitize=undefined</tt></a>.
|
||||
|
||||
<dt id="opt_fno-assume-sane-operator-new"><b>-fno-assume-sane-operator-new</b>:
|
||||
Don't assume that the C++'s new operator is sane.</dt>
|
||||
|
@ -1,96 +1,355 @@
|
||||
Inlining
|
||||
========
|
||||
|
||||
Inlining Modes
|
||||
-----------------------
|
||||
-analyzer-ipa=none - All inlining is disabled.
|
||||
-analyzer-ipa=inlining - Turns on inlining when we can confidently find the function/method body corresponding to the call. (C functions, static functions, devirtualized C++ methods, ObjC class methods, ObjC instance methods when we are confident about the dynamic type of the instance).
|
||||
-analyzer-ipa=dynamic - Inline instance methods for which the type is determined at runtime and we are not 100% sure that our type info is correct. For virtual calls, inline the most plausible definition.
|
||||
-analyzer-ipa=dynamic-bifurcate - Same as -analyzer-ipa=dynamic, but the path is split. We inline on one branch and do not inline on the other. This mode does not drop the coverage in cases when the parent class has code that is only exercised when some of its methods are overriden.
|
||||
There are several options that control which calls the analyzer will consider for
|
||||
inlining. The major one is -analyzer-ipa:
|
||||
|
||||
-analyzer-ipa=none - All inlining is disabled. This is the only mode available
|
||||
in LLVM 3.1 and earlier and in Xcode 4.3 and earlier.
|
||||
|
||||
-analyzer-ipa=basic-inlining - Turns on inlining for C functions, C++ static
|
||||
member functions, and blocks -- essentially, the calls that behave like
|
||||
simple C function calls. This is essentially the mode used in Xcode 4.4.
|
||||
|
||||
-analyzer-ipa=inlining - Turns on inlining when we can confidently find the
|
||||
function/method body corresponding to the call. (C functions, static
|
||||
functions, devirtualized C++ methods, Objective-C class methods, Objective-C
|
||||
instance methods when ExprEngine is confident about the dynamic type of the
|
||||
instance).
|
||||
|
||||
-analyzer-ipa=dynamic - Inline instance methods for which the type is
|
||||
determined at runtime and we are not 100% sure that our type info is
|
||||
correct. For virtual calls, inline the most plausible definition.
|
||||
|
||||
-analyzer-ipa=dynamic-bifurcate - Same as -analyzer-ipa=dynamic, but the path
|
||||
is split. We inline on one branch and do not inline on the other. This mode
|
||||
does not drop the coverage in cases when the parent class has code that is
|
||||
only exercised when some of its methods are overridden.
|
||||
|
||||
Currently, -analyzer-ipa=dynamic-bifurcate is the default mode.
|
||||
|
||||
While -analyzer-ipa determines in general how aggressively the analyzer will try to
|
||||
inline functions, several additional options control which types of functions can
|
||||
inlined, in an all-or-nothing way. These options use the analyzer's configuration
|
||||
table, so they are all specified as follows:
|
||||
|
||||
-analyzer-config OPTION=VALUE
|
||||
|
||||
### c++-inlining ###
|
||||
|
||||
This option controls which C++ member functions may be inlined.
|
||||
|
||||
-analyzer-config c++-inlining=[none | methods | constructors | destructors]
|
||||
|
||||
Each of these modes implies that all the previous member function kinds will be
|
||||
inlined as well; it doesn't make sense to inline destructors without inlining
|
||||
constructors, for example.
|
||||
|
||||
The default c++-inlining mode is 'methods', meaning only regular member
|
||||
functions and overloaded operators will be inlined. Note that no C++ member
|
||||
functions will be inlined under -analyzer-ipa=none or
|
||||
-analyzer-ipa=basic-inlining.
|
||||
|
||||
### c++-template-inlining ###
|
||||
|
||||
This option controls whether C++ templated functions may be inlined.
|
||||
|
||||
-analyzer-config c++-template-inlining=[true | false]
|
||||
|
||||
Currently, template functions are considered for inlining by default.
|
||||
|
||||
The motivation behind this option is that very generic code can be a source
|
||||
of false positives, either by considering paths that the caller considers
|
||||
impossible (by some unstated precondition), or by inlining some but not all
|
||||
of a deep implementation of a function.
|
||||
|
||||
### c++-stdlib-inlining ###
|
||||
|
||||
This option controls whether functions from the C++ standard library, including
|
||||
methods of the container classes in the Standard Template Library, should be
|
||||
considered for inlining.
|
||||
|
||||
-analyzer-config c++-template-inlining=[true | false]
|
||||
|
||||
Currently, C++ standard library functions are NOT considered for inlining by default.
|
||||
|
||||
The standard library functions and the STL in particular are used ubiquitously
|
||||
enough that our tolerance for false positives is even lower here. A false
|
||||
positive due to poor modeling of the STL leads to a poor user experience, since
|
||||
most users would not be comfortable adding assertions to system headers in order
|
||||
to silence analyzer warnings.
|
||||
|
||||
Currently, -analyzer-ipa=inlining is the default mode.
|
||||
|
||||
Basics of Implementation
|
||||
-----------------------
|
||||
|
||||
The low-level mechanism of inlining a function is handled in ExprEngine::inlineCall and ExprEngine::processCallExit. If the conditions are right for inlining, a CallEnter node is created and added to the analysis work list. The CallEnter node marks the change to a new LocationContext representing the called function, and its state includes the contents of the new stack frame. When the CallEnter node is actually processed, its single successor will be a edge to the first CFG block in the function.
|
||||
The low-level mechanism of inlining a function is handled in
|
||||
ExprEngine::inlineCall and ExprEngine::processCallExit.
|
||||
|
||||
Exiting an inlined function is a bit more work, fortunately broken up into reasonable steps:
|
||||
1. The CoreEngine realizes we're at the end of an inlined call and generates a CallExitBegin node.
|
||||
2. ExprEngine takes over (in processCallExit) and finds the return value of the function, if it has one. This is bound to the expression that triggered the call. (In the case of calls without origin expressions, such as destructors, this step is skipped.)
|
||||
3. Dead symbols and bindings are cleaned out from the state, including any local bindings.
|
||||
4. A CallExitEnd node is generated, which marks the transition back to the caller's LocationContext.
|
||||
5. Custom post-call checks are processed and the final nodes are pushed back onto the work list, so that evaluation of the caller can continue.
|
||||
If the conditions are right for inlining, a CallEnter node is created and added
|
||||
to the analysis work list. The CallEnter node marks the change to a new
|
||||
LocationContext representing the called function, and its state includes the
|
||||
contents of the new stack frame. When the CallEnter node is actually processed,
|
||||
its single successor will be a edge to the first CFG block in the function.
|
||||
|
||||
Exiting an inlined function is a bit more work, fortunately broken up into
|
||||
reasonable steps:
|
||||
|
||||
1. The CoreEngine realizes we're at the end of an inlined call and generates a
|
||||
CallExitBegin node.
|
||||
|
||||
2. ExprEngine takes over (in processCallExit) and finds the return value of the
|
||||
function, if it has one. This is bound to the expression that triggered the
|
||||
call. (In the case of calls without origin expressions, such as destructors,
|
||||
this step is skipped.)
|
||||
|
||||
3. Dead symbols and bindings are cleaned out from the state, including any local
|
||||
bindings.
|
||||
|
||||
4. A CallExitEnd node is generated, which marks the transition back to the
|
||||
caller's LocationContext.
|
||||
|
||||
5. Custom post-call checks are processed and the final nodes are pushed back
|
||||
onto the work list, so that evaluation of the caller can continue.
|
||||
|
||||
Retry Without Inlining
|
||||
----------------------
|
||||
|
||||
In some cases, we would like to retry analysis without inlining a particular
|
||||
call.
|
||||
|
||||
Currently, we use this technique to recover coverage in case we stop
|
||||
analyzing a path due to exceeding the maximum block count inside an inlined
|
||||
function.
|
||||
|
||||
When this situation is detected, we walk up the path to find the first node
|
||||
before inlining was started and enqueue it on the WorkList with a special
|
||||
ReplayWithoutInlining bit added to it (ExprEngine::replayWithoutInlining). The
|
||||
path is then re-analyzed from that point without inlining that particular call.
|
||||
|
||||
Deciding When to Inline
|
||||
-----------------------
|
||||
|
||||
In some cases, we would like to retry analyzes without inlining the particular call. Currently, we use this technique to recover the coverage in case we stop analyzing a path due to exceeding the maximum block count inside an inlined function. When this situation is detected, we walk up the path to find the first node before inlining was started and enqueue it on the WorkList with a special ReplayWithoutInlining bit added to it (ExprEngine::replayWithoutInlining).
|
||||
In general, the analyzer attempts to inline as much as possible, since it
|
||||
provides a better summary of what actually happens in the program. There are
|
||||
some cases, however, where the analyzer chooses not to inline:
|
||||
|
||||
Deciding when to inline
|
||||
-----------------------
|
||||
In general, we try to inline as much as possible, since it provides a better summary of what actually happens in the program. However, there are some cases where we choose not to inline:
|
||||
- if there is no definition available (of course)
|
||||
- if we can't create a CFG or compute variable liveness for the function
|
||||
- if we reach a cutoff of maximum stack depth (to avoid infinite recursion)
|
||||
- if the function is variadic
|
||||
- in C++, we don't inline constructors unless we know the destructor will be inlined as well
|
||||
- in C++, we don't inline allocators (custom operator new implementations), since we don't properly handle deallocators (at the time of this writing)
|
||||
- "Dynamic" calls are handled specially; see below.
|
||||
- Engine:FunctionSummaries map stores additional information about declarations, some of which is collected at runtime based on previous analyzes of the function. We do not inline functions which were not profitable to inline in a different context (for example, if the maximum block count was exceeded, see Retry Without Inlining).
|
||||
- If there is no definition available for the called function or method. In
|
||||
this case, there is no opportunity to inline.
|
||||
|
||||
- If the CFG cannot be constructed for a called function, or the liveness
|
||||
cannot be computed. These are prerequisites for analyzing a function body,
|
||||
with or without inlining.
|
||||
|
||||
- If the LocationContext chain for a given ExplodedNode reaches a maximum cutoff
|
||||
depth. This prevents unbounded analysis due to infinite recursion, but also
|
||||
serves as a useful cutoff for performance reasons.
|
||||
|
||||
- If the function is variadic. This is not a hard limitation, but an engineering
|
||||
limitation.
|
||||
|
||||
Tracked by: <rdar://problem/12147064> Support inlining of variadic functions
|
||||
|
||||
- In C++, constructors are not inlined unless the destructor call will be
|
||||
processed by the ExprEngine. Thus, if the CFG was built without nodes for
|
||||
implicit destructors, or if the destructors for the given object are not
|
||||
represented in the CFG, the constructor will not be inlined. (As an exception,
|
||||
constructors for objects with trivial constructors can still be inlined.)
|
||||
See "C++ Caveats" below.
|
||||
|
||||
- In C++, ExprEngine does not inline custom implementations of operator 'new'
|
||||
or operator 'delete', nor does it inline the constructors and destructors
|
||||
associated with these. See "C++ Caveats" below.
|
||||
|
||||
- Calls resulting in "dynamic dispatch" are specially handled. See more below.
|
||||
|
||||
- The FunctionSummaries map stores additional information about declarations,
|
||||
some of which is collected at runtime based on previous analyses.
|
||||
We do not inline functions which were not profitable to inline in a different
|
||||
context (for example, if the maximum block count was exceeded; see
|
||||
"Retry Without Inlining").
|
||||
|
||||
|
||||
Dynamic calls and devirtualization
|
||||
Dynamic Calls and Devirtualization
|
||||
----------------------------------
|
||||
"Dynamic" calls are those that are resolved at runtime, such as C++ virtual method calls and Objective-C message sends. Due to the path-sensitive nature of the analyzer, we may be able to figure out the dynamic type of the object whose method is being called and thus "devirtualize" the call, i.e. find the actual method that will be called at runtime. (Obviously this is not always possible.) This is handled by CallEvent's getRuntimeDefinition method.
|
||||
|
||||
Type information is tracked as DynamicTypeInfo, stored within the program state. If no DynamicTypeInfo has been explicitly set for a region, it will be inferred from the region's type or associated symbol. Information from symbolic regions is weaker than from true typed regions; a C++ object declared "A obj" is known to have the class 'A', but a reference "A &ref" may dynamically be a subclass of 'A'. The DynamicTypePropagation checker gathers and propagates the type information.
|
||||
"Dynamic" calls are those that are resolved at runtime, such as C++ virtual
|
||||
method calls and Objective-C message sends. Due to the path-sensitive nature of
|
||||
the analysis, the analyzer may be able to reason about the dynamic type of the
|
||||
object whose method is being called and thus "devirtualize" the call.
|
||||
|
||||
(Warning: not all of the existing analyzer code has been retrofitted to use DynamicTypeInfo, nor is it universally appropriate. In particular, DynamicTypeInfo always applies to a region with all casts stripped off, but sometimes the information provided by casts can be useful.)
|
||||
This path-sensitive devirtualization occurs when the analyzer can determine what
|
||||
method would actually be called at runtime. This is possible when the type
|
||||
information is constrained enough for a simulated C++/Objective-C object that
|
||||
the analyzer can make such a decision.
|
||||
|
||||
When asked to provide a definition, the CallEvents for dynamic calls will use the type info in their state to provide the best definition of the method to be called. In some cases this devirtualization can be perfect or near-perfect, and we can inline the definition as usual. In others we can make a guess, but report that our guess may not be the method actually called at runtime.
|
||||
== DynamicTypeInfo ==
|
||||
|
||||
The -analyzer-ipa option has four different modes: none, inlining, dynamic, and dynamic-bifurcate. Under -analyzer-ipa=dynamic, all dynamic calls are inlined, whether we are certain or not that this will actually be the definition used at runtime. Under -analyzer-ipa=inlining, only "near-perfect" devirtualized calls are inlined*, and other dynamic calls are evaluated conservatively (as if no definition were available).
|
||||
As the analyzer analyzes a path, it may accrue information to refine the
|
||||
knowledge about the type of an object. This can then be used to make better
|
||||
decisions about the target method of a call.
|
||||
|
||||
* Currently, no Objective-C messages are not inlined under -analyzer-ipa=inlining, even if we are reasonably confident of the type of the receiver. We plan to enable this once we have tested our heuristics more thoroughly.
|
||||
Such type information is tracked as DynamicTypeInfo. This is path-sensitive
|
||||
data that is stored in ProgramState, which defines a mapping from MemRegions to
|
||||
an (optional) DynamicTypeInfo.
|
||||
|
||||
The last option, -analyzer-ipa=dynamic-bifurcate, behaves similarly to "dynamic", but performs a conservative invalidation in the general virtual case in /addition/ to inlining. The details of this are discussed below.
|
||||
If no DynamicTypeInfo has been explicitly set for a MemRegion, it will be lazily
|
||||
inferred from the region's type or associated symbol. Information from symbolic
|
||||
regions is weaker than from true typed regions.
|
||||
|
||||
EXAMPLE: A C++ object declared "A obj" is known to have the class 'A', but a
|
||||
reference "A &ref" may dynamically be a subclass of 'A'.
|
||||
|
||||
The DynamicTypePropagation checker gathers and propagates DynamicTypeInfo,
|
||||
updating it as information is observed along a path that can refine that type
|
||||
information for a region.
|
||||
|
||||
WARNING: Not all of the existing analyzer code has been retrofitted to use
|
||||
DynamicTypeInfo, nor is it universally appropriate. In particular,
|
||||
DynamicTypeInfo always applies to a region with all casts stripped
|
||||
off, but sometimes the information provided by casts can be useful.
|
||||
|
||||
|
||||
== RuntimeDefinition ==
|
||||
|
||||
The basis of devirtualization is CallEvent's getRuntimeDefinition() method,
|
||||
which returns a RuntimeDefinition object. When asked to provide a definition,
|
||||
the CallEvents for dynamic calls will use the DynamicTypeInfo in their
|
||||
ProgramState to attempt to devirtualize the call. In the case of no dynamic
|
||||
dispatch, or perfectly constrained devirtualization, the resulting
|
||||
RuntimeDefinition contains a Decl corresponding to the definition of the called
|
||||
function, and RuntimeDefinition::mayHaveOtherDefinitions will return FALSE.
|
||||
|
||||
In the case of dynamic dispatch where our information is not perfect, CallEvent
|
||||
can make a guess, but RuntimeDefinition::mayHaveOtherDefinitions will return
|
||||
TRUE. The RuntimeDefinition object will then also include a MemRegion
|
||||
corresponding to the object being called (i.e., the "receiver" in Objective-C
|
||||
parlance), which ExprEngine uses to decide whether or not the call should be
|
||||
inlined.
|
||||
|
||||
== Inlining Dynamic Calls ==
|
||||
|
||||
The -analyzer-ipa option has five different modes: none, basic-inlining,
|
||||
inlining, dynamic, and dynamic-bifurcate. Under -analyzer-ipa=dynamic, all
|
||||
dynamic calls are inlined, whether we are certain or not that this will actually
|
||||
be the definition used at runtime. Under -analyzer-ipa=inlining, only
|
||||
"near-perfect" devirtualized calls are inlined*, and other dynamic calls are
|
||||
evaluated conservatively (as if no definition were available).
|
||||
|
||||
* Currently, no Objective-C messages are not inlined under
|
||||
-analyzer-ipa=inlining, even if we are reasonably confident of the type of the
|
||||
receiver. We plan to enable this once we have tested our heuristics more
|
||||
thoroughly.
|
||||
|
||||
The last option, -analyzer-ipa=dynamic-bifurcate, behaves similarly to
|
||||
"dynamic", but performs a conservative invalidation in the general virtual case
|
||||
in *addition* to inlining. The details of this are discussed below.
|
||||
|
||||
As stated above, -analyzer-ipa=basic-inlining does not inline any C++ member
|
||||
functions or Objective-C method calls, even if they are non-virtual or can be
|
||||
safely devirtualized.
|
||||
|
||||
|
||||
Bifurcation
|
||||
-----------
|
||||
ExprEngine::BifurcateCall implements the -analyzer-ipa=dynamic-bifurcate mode. When a call is made on a region with dynamic type information, we bifurcate the path and add the region's processing mode to the GDM. Currently, there are 2 modes: DynamicDispatchModeInlined and DynamicDispatchModeConservative. Going forward, we consult the state of the region to make decisions on whether the calls should be inlined or not, which ensures that we have at most one split per region. The modes model the cases when the dynamic type information is perfectly correct and when the info is not correct (i.e. where the region is a subclass of the type we store in DynamicTypeInfo).
|
||||
|
||||
Bifurcation mode allows for increased coverage in cases where the parent method contains code which is only executed when the class is subclassed. The disadvantages of this mode are a (considerable?) performance hit and the possibility of false positives on the path where the conservative mode is used.
|
||||
ExprEngine::BifurcateCall implements the -analyzer-ipa=dynamic-bifurcate
|
||||
mode.
|
||||
|
||||
When a call is made on an object with imprecise dynamic type information
|
||||
(RuntimeDefinition::mayHaveOtherDefinitions() evaluates to TRUE), ExprEngine
|
||||
bifurcates the path and marks the object's region (retrieved from the
|
||||
RuntimeDefinition object) with a path-sensitive "mode" in the ProgramState.
|
||||
|
||||
Currently, there are 2 modes:
|
||||
|
||||
DynamicDispatchModeInlined - Models the case where the dynamic type information
|
||||
of the receiver (MemoryRegion) is assumed to be perfectly constrained so
|
||||
that a given definition of a method is expected to be the code actually
|
||||
called. When this mode is set, ExprEngine uses the Decl from
|
||||
RuntimeDefinition to inline any dynamically dispatched call sent to this
|
||||
receiver because the function definition is considered to be fully resolved.
|
||||
|
||||
DynamicDispatchModeConservative - Models the case where the dynamic type
|
||||
information is assumed to be incorrect, for example, implies that the method
|
||||
definition is overriden in a subclass. In such cases, ExprEngine does not
|
||||
inline the methods sent to the receiver (MemoryRegion), even if a candidate
|
||||
definition is available. This mode is conservative about simulating the
|
||||
effects of a call.
|
||||
|
||||
Going forward along the symbolic execution path, ExprEngine consults the mode
|
||||
of the receiver's MemRegion to make decisions on whether the calls should be
|
||||
inlined or not, which ensures that there is at most one split per region.
|
||||
|
||||
At a high level, "bifurcation mode" allows for increased semantic coverage in
|
||||
cases where the parent method contains code which is only executed when the
|
||||
class is subclassed. The disadvantages of this mode are a (considerable?)
|
||||
performance hit and the possibility of false positives on the path where the
|
||||
conservative mode is used.
|
||||
|
||||
Objective-C Message Heuristics
|
||||
------------------------------
|
||||
We rely on a set of heuristics to partition the set of ObjC method calls into ones that require bifurcation and ones that do not (can or cannot be a subclass). Below are the cases when we consider that the dynamic type of the object is precise (cannot be a subclass):
|
||||
- If the object was created with +alloc or +new and initialized with an -init method.
|
||||
- If the calls are property accesses using dot syntax. This is based on the assumption that children rarely override properties, or do so in an essentially compatible way.
|
||||
- If the class interface is declared inside the main source file. In this case it is unlikely that it will be subclassed.
|
||||
- If the method is not declared outside of main source file, either by the receiver's class or by any superclasses.
|
||||
|
||||
ExprEngine relies on a set of heuristics to partition the set of Objective-C
|
||||
method calls into those that require bifurcation and those that do not. Below
|
||||
are the cases when the DynamicTypeInfo of the object is considered precise
|
||||
(cannot be a subclass):
|
||||
|
||||
C++ Inlining Caveats
|
||||
- If the object was created with +alloc or +new and initialized with an -init
|
||||
method.
|
||||
|
||||
- If the calls are property accesses using dot syntax. This is based on the
|
||||
assumption that children rarely override properties, or do so in an
|
||||
essentially compatible way.
|
||||
|
||||
- If the class interface is declared inside the main source file. In this case
|
||||
it is unlikely that it will be subclassed.
|
||||
|
||||
- If the method is not declared outside of main source file, either by the
|
||||
receiver's class or by any superclasses.
|
||||
|
||||
C++ Caveats
|
||||
--------------------
|
||||
C++11 [class.cdtor]p4 describes how the vtable of an object is modified as it is being constructed or destructed; that is, the type of the object depends on which base constructors have been completed. This is tracked using dynamic type info in the DynamicTypePropagation checker.
|
||||
|
||||
Temporaries are poorly modelled right now because we're not confident in the placement
|
||||
C++11 [class.cdtor]p4 describes how the vtable of an object is modified as it is
|
||||
being constructed or destructed; that is, the type of the object depends on
|
||||
which base constructors have been completed. This is tracked using
|
||||
DynamicTypeInfo in the DynamicTypePropagation checker.
|
||||
|
||||
'new' is poorly modelled due to some nasty CFG/design issues (elaborated in PR12014). 'delete' is essentially not modelled at all.
|
||||
There are several limitations in the current implementation:
|
||||
|
||||
Arrays of objects are modeled very poorly right now. We run only the first constructor and first destructor. Because of this, we don't inline any constructors or destructors for arrays.
|
||||
- Temporaries are poorly modeled right now because we're not confident in the
|
||||
placement of their destructors in the CFG. We currently won't inline their
|
||||
constructors unless the destructor is trivial, and don't process their
|
||||
destructors at all, not even to invalidate the region.
|
||||
|
||||
- 'new' is poorly modeled due to some nasty CFG/design issues. This is tracked
|
||||
in PR12014. 'delete' is not modeled at all.
|
||||
|
||||
- Arrays of objects are modeled very poorly right now. ExprEngine currently
|
||||
only simulates the first constructor and first destructor. Because of this,
|
||||
ExprEngine does not inline any constructors or destructors for arrays.
|
||||
|
||||
|
||||
CallEvent
|
||||
=========
|
||||
|
||||
A CallEvent represents a specific call to a function, method, or other body of code. It is path-sensitive, containing both the current state (ProgramStateRef) and stack space (LocationContext), and provides uniform access to the argument values and return type of a call, no matter how the call is written in the source or what sort of code body is being invoked.
|
||||
A CallEvent represents a specific call to a function, method, or other body of
|
||||
code. It is path-sensitive, containing both the current state (ProgramStateRef)
|
||||
and stack space (LocationContext), and provides uniform access to the argument
|
||||
values and return type of a call, no matter how the call is written in the
|
||||
source or what sort of code body is being invoked.
|
||||
|
||||
(For those familiar with Cocoa, CallEvent is roughly equivalent to NSInvocation.)
|
||||
NOTE: For those familiar with Cocoa, CallEvent is roughly equivalent to
|
||||
NSInvocation.
|
||||
|
||||
CallEvent should be used whenever there is logic dealing with function calls that does not care how the call occurred. Examples include checking that arguments satisfy preconditions (such as __attribute__((nonnull))), and attempting to inline a call.
|
||||
CallEvent should be used whenever there is logic dealing with function calls
|
||||
that does not care how the call occurred.
|
||||
|
||||
CallEvents are reference-counted objects managed by a CallEventManager. While there is no inherent issue with persisting them (say, in the state's GDM), they are intended for short-lived use, and can be recreated from CFGElements or StackFrameContexts fairly easily.
|
||||
Examples include checking that arguments satisfy preconditions (such as
|
||||
__attribute__((nonnull))), and attempting to inline a call.
|
||||
|
||||
CallEvents are reference-counted objects managed by a CallEventManager. While
|
||||
there is no inherent issue with persisting them (say, in a ProgramState's GDM),
|
||||
they are intended for short-lived use, and can be recreated from CFGElements or
|
||||
non-top-level StackFrameContexts fairly easily.
|
||||
|
89
docs/analyzer/debug-checks.txt
Normal file
89
docs/analyzer/debug-checks.txt
Normal file
@ -0,0 +1,89 @@
|
||||
The analyzer contains a number of checkers which can aid in debugging. Enable them by using the "-analyzer-checker=" flag, followed by the name of the checker.
|
||||
|
||||
General Analysis Dumpers
|
||||
========================
|
||||
These checkers are used to dump the results of various infrastructural analyses to stderr. Some checkers also have "view" variants, which will display a graph using a 'dot' format viewer (such as Graphviz on OS X) instead.
|
||||
|
||||
- debug.DumpCallGraph, debug.ViewCallGraph: Show the call graph generated for the current translation unit. This is used to determine the order in which to analyze functions when inlining is enabled.
|
||||
- debug.DumpCFG, debug.ViewCFG: Show the CFG generated for each top-level function being analyzed.
|
||||
- debug.DumpDominators: Shows the dominance tree for the CFG of each top-level function.
|
||||
- debug.DumpLiveVars: Show the results of live variable analysis for each top-level function being analyzed.
|
||||
|
||||
|
||||
Path Tracking
|
||||
=============
|
||||
These checkers print information about the path taken by the analyzer engine.
|
||||
|
||||
- debug.DumpCalls: Prints out every function or method call encountered during a path traversal. This is indented to show the call stack, but does NOT do any special handling of branches, meaning different paths could end up interleaved.
|
||||
- debug.DumpTraversal: Prints the name of each branch statement encountered during a path traversal ("IfStmt", "WhileStmt", etc). Currently used to check whether the analysis engine is doing BFS or DFS.
|
||||
|
||||
|
||||
State Checking
|
||||
==============
|
||||
These checkers will print out information about the analyzer state in the form of analysis warnings. They are intended for use with the -verify functionality in regression tests.
|
||||
|
||||
- debug.TaintTest: Prints out the word "tainted" for every expression that carries taint. At the time of this writing, taint was only introduced by the checks under experimental.security.taint.TaintPropagation; this checker may eventually move to the security.taint package.
|
||||
- debug.ExprInspection: Responds to certain function calls, which are modeled after builtins. These function calls should affect the program state other than the evaluation of their arguments; to use them, you will need to declare them within your test file. The available functions are described below.
|
||||
|
||||
(FIXME: debug.ExprInspection should probably be renamed, since it no longer only inspects expressions.)
|
||||
|
||||
|
||||
ExprInspection checks
|
||||
---------------------
|
||||
|
||||
- void clang_analyzer_eval(bool);
|
||||
|
||||
Prints TRUE if the argument is known to have a non-zero value,
|
||||
FALSE if the argument is known to have a zero or null value, and
|
||||
UNKNOWN if the argument isn't sufficiently constrained on this path.
|
||||
You can use this to test other values by using expressions like "x == 5".
|
||||
Note that this functionality is currently DISABLED in inlined functions,
|
||||
since different calls to the same inlined function could provide different
|
||||
information, making it difficult to write proper -verify directives.
|
||||
|
||||
In C, the argument can be typed as 'int' or as '_Bool'.
|
||||
|
||||
Example usage:
|
||||
clang_analyzer_eval(x); // expected-warning{{UNKNOWN}}
|
||||
if (!x) return;
|
||||
clang_analyzer_eval(x); // expected-warning{{TRUE}}
|
||||
|
||||
|
||||
- void clang_analyzer_checkInlined(bool);
|
||||
|
||||
If a call occurs within an inlined function, prints TRUE or FALSE according to
|
||||
the value of its argument. If a call occurs outside an inlined function,
|
||||
nothing is printed.
|
||||
|
||||
The intended use of this checker is to assert that a function is inlined at
|
||||
least once (by passing 'true' and expecting a warning), or to assert that a
|
||||
function is never inlined (by passing 'false' and expecting no warning). The
|
||||
argument is technically unnecessary but is intended to clarify intent.
|
||||
|
||||
You might wonder why we can't print TRUE if a function is ever inlined and
|
||||
FALSE if it is not. The problem is that any inlined function could conceivably
|
||||
also be analyzed as a top-level function (in which case both TRUE and FALSE
|
||||
would be printed), depending on the value of the -analyzer-inlining option.
|
||||
|
||||
In C, the argument can be typed as 'int' or as '_Bool'.
|
||||
|
||||
Example usage:
|
||||
int inlined() {
|
||||
clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
|
||||
return 42;
|
||||
}
|
||||
|
||||
void topLevel() {
|
||||
clang_analyzer_checkInlined(false); // no-warning (not inlined)
|
||||
int value = inlined();
|
||||
// This assertion will not be valid if the previous call was not inlined.
|
||||
clang_analyzer_eval(value == 42); // expected-warning{{TRUE}}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Statistics
|
||||
==========
|
||||
The debug.Stats checker collects various information about the analysis of each function, such as how many blocks were reached and if the analyzer timed out.
|
||||
|
||||
There is also an additional -analyzer-stats flag, which enables various statistics within the analyzer engine. Note the Stats checker (which produces at least one bug report per function) may actually change the values reported by -analyzer-stats.
|
@ -132,7 +132,7 @@ Treat subsequent input files as having type I<language>.
|
||||
|
||||
Specify the language standard to compile for.
|
||||
|
||||
=item B<-stdlib>=I<language>
|
||||
=item B<-stdlib>=I<library>
|
||||
|
||||
Specify the C++ standard library to use; supported options are libstdc++ and
|
||||
libc++.
|
||||
|
264
docs/tools/dump_ast_matchers.py
Normal file
264
docs/tools/dump_ast_matchers.py
Normal file
@ -0,0 +1,264 @@
|
||||
#!/usr/bin/env python
|
||||
# A tool to parse ASTMatchers.h and update the documentation in
|
||||
# ../LibASTMatchersReference.html automatically. Run from the
|
||||
# directory in which this file is located to update the docs.
|
||||
|
||||
import collections
|
||||
import re
|
||||
import urllib2
|
||||
|
||||
MATCHERS_FILE = '../../include/clang/ASTMatchers/ASTMatchers.h'
|
||||
|
||||
# Each matcher is documented in one row of the form:
|
||||
# result | name | argA
|
||||
# The subsequent row contains the documentation and is hidden by default,
|
||||
# becoming visible via javascript when the user clicks the matcher name.
|
||||
TD_TEMPLATE="""
|
||||
<tr><td>%(result)s</td><td class="name" onclick="toggle('%(id)s')"><a name="%(id)sAnchor">%(name)s</a></td><td>%(args)s</td></tr>
|
||||
<tr><td colspan="4" class="doc" id="%(id)s"><pre>%(comment)s</pre></td></tr>
|
||||
"""
|
||||
|
||||
# We categorize the matchers into these three categories in the reference:
|
||||
node_matchers = {}
|
||||
narrowing_matchers = {}
|
||||
traversal_matchers = {}
|
||||
|
||||
# We output multiple rows per matcher if the matcher can be used on multiple
|
||||
# node types. Thus, we need a new id per row to control the documentation
|
||||
# pop-up. ids[name] keeps track of those ids.
|
||||
ids = collections.defaultdict(int)
|
||||
|
||||
# Cache for doxygen urls we have already verified.
|
||||
doxygen_probes = {}
|
||||
|
||||
def esc(text):
|
||||
"""Escape any html in the given text."""
|
||||
text = re.sub(r'&', '&', text)
|
||||
text = re.sub(r'<', '<', text)
|
||||
text = re.sub(r'>', '>', text)
|
||||
def link_if_exists(m):
|
||||
name = m.group(1)
|
||||
url = 'http://clang.llvm.org/doxygen/classclang_1_1%s.html' % name
|
||||
if url not in doxygen_probes:
|
||||
try:
|
||||
print 'Probing %s...' % url
|
||||
urllib2.urlopen(url)
|
||||
doxygen_probes[url] = True
|
||||
except:
|
||||
doxygen_probes[url] = False
|
||||
if doxygen_probes[url]:
|
||||
return r'Matcher<<a href="%s">%s</a>>' % (url, name)
|
||||
else:
|
||||
return m.group(0)
|
||||
text = re.sub(
|
||||
r'Matcher<([^\*&]+)>', link_if_exists, text)
|
||||
return text
|
||||
|
||||
def extract_result_types(comment):
|
||||
"""Extracts a list of result types from the given comment.
|
||||
|
||||
We allow annotations in the comment of the matcher to specify what
|
||||
nodes a matcher can match on. Those comments have the form:
|
||||
Usable as: Any Matcher | (Matcher<T1>[, Matcher<t2>[, ...]])
|
||||
|
||||
Returns ['*'] in case of 'Any Matcher', or ['T1', 'T2', ...].
|
||||
Returns the empty list if no 'Usable as' specification could be
|
||||
parsed.
|
||||
"""
|
||||
result_types = []
|
||||
m = re.search(r'Usable as: Any Matcher[\s\n]*$', comment, re.S)
|
||||
if m:
|
||||
return ['*']
|
||||
while True:
|
||||
m = re.match(r'^(.*)Matcher<([^>]+)>\s*,?[\s\n]*$', comment, re.S)
|
||||
if not m:
|
||||
if re.search(r'Usable as:\s*$', comment):
|
||||
return result_types
|
||||
else:
|
||||
return None
|
||||
result_types += [m.group(2)]
|
||||
comment = m.group(1)
|
||||
|
||||
def strip_doxygen(comment):
|
||||
"""Returns the given comment without \-escaped words."""
|
||||
# If there is only a doxygen keyword in the line, delete the whole line.
|
||||
comment = re.sub(r'^\\[^\s]+\n', r'', comment, flags=re.M)
|
||||
# Delete the doxygen command and the following whitespace.
|
||||
comment = re.sub(r'\\[^\s]+\s+', r'', comment)
|
||||
return comment
|
||||
|
||||
def unify_arguments(args):
|
||||
"""Gets rid of anything the user doesn't care about in the argument list."""
|
||||
args = re.sub(r'internal::', r'', args)
|
||||
args = re.sub(r'const\s+', r'', args)
|
||||
args = re.sub(r'&', r' ', args)
|
||||
args = re.sub(r'(^|\s)M\d?(\s)', r'\1Matcher<*>\2', args)
|
||||
return args
|
||||
|
||||
def add_matcher(result_type, name, args, comment, is_dyncast=False):
|
||||
"""Adds a matcher to one of our categories."""
|
||||
if name == 'id':
|
||||
# FIXME: Figure out whether we want to support the 'id' matcher.
|
||||
return
|
||||
matcher_id = '%s%d' % (name, ids[name])
|
||||
ids[name] += 1
|
||||
args = unify_arguments(args)
|
||||
matcher_html = TD_TEMPLATE % {
|
||||
'result': esc('Matcher<%s>' % result_type),
|
||||
'name': name,
|
||||
'args': esc(args),
|
||||
'comment': esc(strip_doxygen(comment)),
|
||||
'id': matcher_id,
|
||||
}
|
||||
if is_dyncast:
|
||||
node_matchers[result_type + name] = matcher_html
|
||||
# Use a heuristic to figure out whether a matcher is a narrowing or
|
||||
# traversal matcher. By default, matchers that take other matchers as
|
||||
# arguments (and are not node matchers) do traversal. We specifically
|
||||
# exclude known narrowing matchers that also take other matchers as
|
||||
# arguments.
|
||||
elif ('Matcher<' not in args or
|
||||
name in ['allOf', 'anyOf', 'anything', 'unless']):
|
||||
narrowing_matchers[result_type + name] = matcher_html
|
||||
else:
|
||||
traversal_matchers[result_type + name] = matcher_html
|
||||
|
||||
def act_on_decl(declaration, comment, allowed_types):
|
||||
"""Parse the matcher out of the given declaration and comment.
|
||||
|
||||
If 'allowed_types' is set, it contains a list of node types the matcher
|
||||
can match on, as extracted from the static type asserts in the matcher
|
||||
definition.
|
||||
"""
|
||||
if declaration.strip():
|
||||
# Node matchers are defined by writing:
|
||||
# VariadicDynCastAllOfMatcher<ResultType, ArgumentType> name;
|
||||
m = re.match(r""".*VariadicDynCastAllOfMatcher\s*<
|
||||
\s*([^\s,]+)\s*,
|
||||
\s*([^\s>]+)\s*>
|
||||
\s*([^\s;]+)\s*;\s*$""", declaration, flags=re.X)
|
||||
if m:
|
||||
result, inner, name = m.groups()
|
||||
add_matcher(result, name, 'Matcher<%s>...' % inner,
|
||||
comment, is_dyncast=True)
|
||||
return
|
||||
|
||||
# Parse the various matcher definition macros.
|
||||
m = re.match(r"""^\s*AST_(POLYMORPHIC_)?MATCHER(_P)?(.?)\(
|
||||
(?:\s*([^\s,]+)\s*,)?
|
||||
\s*([^\s,]+)\s*
|
||||
(?:,\s*([^\s,]+)\s*
|
||||
,\s*([^\s,]+)\s*)?
|
||||
(?:,\s*([^\s,]+)\s*
|
||||
,\s*([^\s,]+)\s*)?
|
||||
\)\s*{\s*$""", declaration, flags=re.X)
|
||||
if m:
|
||||
p, n, result, name = m.groups()[1:5]
|
||||
args = m.groups()[5:]
|
||||
if not result:
|
||||
if not allowed_types:
|
||||
raise Exception('Did not find allowed result types for: %s' % name)
|
||||
result_types = allowed_types
|
||||
else:
|
||||
result_types = [result]
|
||||
if n not in ['', '2']:
|
||||
raise Exception('Cannot parse "%s"' % declaration)
|
||||
args = ', '.join('%s %s' % (args[i], args[i+1])
|
||||
for i in range(0, len(args), 2) if args[i])
|
||||
for result_type in result_types:
|
||||
add_matcher(result_type, name, args, comment)
|
||||
return
|
||||
|
||||
# Parse free standing matcher functions, like:
|
||||
# Matcher<ResultType> Name(Matcher<ArgumentType> InnerMatcher) {
|
||||
m = re.match(r"""^\s*(.*)\s+
|
||||
([^\s\(]+)\s*\(
|
||||
(.*)
|
||||
\)\s*{""", declaration, re.X)
|
||||
if m:
|
||||
result, name, args = m.groups()
|
||||
args = ', '.join(p.strip() for p in args.split(','))
|
||||
m = re.match(r'.*\s+internal::Matcher<([^>]+)>$', result)
|
||||
if m:
|
||||
result_types = [m.group(1)]
|
||||
else:
|
||||
result_types = extract_result_types(comment)
|
||||
if not result_types:
|
||||
if not comment:
|
||||
# Only overloads don't have their own doxygen comments; ignore those.
|
||||
print 'Ignoring "%s"' % name
|
||||
else:
|
||||
print 'Cannot determine result type for "%s"' % name
|
||||
else:
|
||||
for result_type in result_types:
|
||||
add_matcher(result_type, name, args, comment)
|
||||
else:
|
||||
print '*** Unparsable: "' + declaration + '" ***'
|
||||
|
||||
def sort_table(matcher_type, matcher_map):
|
||||
"""Returns the sorted html table for the given row map."""
|
||||
table = ''
|
||||
for key in sorted(matcher_map.keys()):
|
||||
table += matcher_map[key] + '\n'
|
||||
return ('<!-- START_%(type)s_MATCHERS -->\n' +
|
||||
'%(table)s' +
|
||||
'<!--END_%(type)s_MATCHERS -->') % {
|
||||
'type': matcher_type,
|
||||
'table': table,
|
||||
}
|
||||
|
||||
# Parse the ast matchers.
|
||||
# We alternate between two modes:
|
||||
# body = True: We parse the definition of a matcher. We need
|
||||
# to parse the full definition before adding a matcher, as the
|
||||
# definition might contain static asserts that specify the result
|
||||
# type.
|
||||
# body = False: We parse the comments and declaration of the matcher.
|
||||
comment = ''
|
||||
declaration = ''
|
||||
allowed_types = []
|
||||
body = False
|
||||
for line in open(MATCHERS_FILE).read().splitlines():
|
||||
if body:
|
||||
if line.strip() and line[0] == '}':
|
||||
if declaration:
|
||||
act_on_decl(declaration, comment, allowed_types)
|
||||
comment = ''
|
||||
declaration = ''
|
||||
allowed_types = []
|
||||
body = False
|
||||
else:
|
||||
m = re.search(r'is_base_of<([^,]+), NodeType>', line)
|
||||
if m and m.group(1):
|
||||
allowed_types += [m.group(1)]
|
||||
continue
|
||||
if line.strip() and line.lstrip()[0] == '/':
|
||||
comment += re.sub(r'/+\s?', '', line) + '\n'
|
||||
else:
|
||||
declaration += ' ' + line
|
||||
if ((not line.strip()) or
|
||||
line.rstrip()[-1] == ';' or
|
||||
line.rstrip()[-1] == '{'):
|
||||
if line.strip() and line.rstrip()[-1] == '{':
|
||||
body = True
|
||||
else:
|
||||
act_on_decl(declaration, comment, allowed_types)
|
||||
comment = ''
|
||||
declaration = ''
|
||||
allowed_types = []
|
||||
|
||||
node_matcher_table = sort_table('DECL', node_matchers)
|
||||
narrowing_matcher_table = sort_table('NARROWING', narrowing_matchers)
|
||||
traversal_matcher_table = sort_table('TRAVERSAL', traversal_matchers)
|
||||
|
||||
reference = open('../LibASTMatchersReference.html').read()
|
||||
reference = re.sub(r'<!-- START_DECL_MATCHERS.*END_DECL_MATCHERS -->',
|
||||
'%s', reference, flags=re.S) % node_matcher_table
|
||||
reference = re.sub(r'<!-- START_NARROWING_MATCHERS.*END_NARROWING_MATCHERS -->',
|
||||
'%s', reference, flags=re.S) % narrowing_matcher_table
|
||||
reference = re.sub(r'<!-- START_TRAVERSAL_MATCHERS.*END_TRAVERSAL_MATCHERS -->',
|
||||
'%s', reference, flags=re.S) % traversal_matcher_table
|
||||
|
||||
with open('../LibASTMatchersReference.html', 'w') as output:
|
||||
output.write(reference)
|
||||
|
@ -39,7 +39,7 @@ void MainCallChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const
|
||||
|
||||
BugReport *report = new BugReport(*BT, BT->getName(), N);
|
||||
report->addRange(Callee->getSourceRange());
|
||||
C.EmitReport(report);
|
||||
C.emitReport(report);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -29,7 +29,8 @@ target_link_libraries(clang-interpreter
|
||||
clangStaticAnalyzerCheckers
|
||||
clangStaticAnalyzerCore
|
||||
clangAnalysis
|
||||
clangRewrite
|
||||
clangRewriteCore
|
||||
clangRewriteFrontend
|
||||
clangAST
|
||||
clangParse
|
||||
clangLex
|
||||
|
@ -20,7 +20,7 @@ LINK_COMPONENTS := jit interpreter nativecodegen bitreader bitwriter ipo \
|
||||
USEDLIBS = clangFrontend.a clangSerialization.a clangDriver.a clangCodeGen.a \
|
||||
clangParse.a clangSema.a clangStaticAnalyzerFrontend.a \
|
||||
clangStaticAnalyzerCheckers.a clangStaticAnalyzerCore.a \
|
||||
clangAnalysis.a clangRewrite.a \
|
||||
clangAnalysis.a clangRewriteCore.a clangRewriteFrontend.a \
|
||||
clangEdit.a clangAST.a clangLex.a clangBasic.a
|
||||
|
||||
include $(CLANG_LEVEL)/Makefile
|
||||
|
@ -13,9 +13,9 @@
|
||||
#include "clang/Driver/Tool.h"
|
||||
#include "clang/Frontend/CompilerInvocation.h"
|
||||
#include "clang/Frontend/CompilerInstance.h"
|
||||
#include "clang/Frontend/DiagnosticOptions.h"
|
||||
#include "clang/Frontend/FrontendDiagnostic.h"
|
||||
#include "clang/Frontend/TextDiagnosticPrinter.h"
|
||||
#include "clang/Basic/DiagnosticOptions.h"
|
||||
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
@ -69,11 +69,12 @@ static int Execute(llvm::Module *Mod, char * const *envp) {
|
||||
int main(int argc, const char **argv, char * const *envp) {
|
||||
void *MainAddr = (void*) (intptr_t) GetExecutablePath;
|
||||
llvm::sys::Path Path = GetExecutablePath(argv[0]);
|
||||
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
|
||||
TextDiagnosticPrinter *DiagClient =
|
||||
new TextDiagnosticPrinter(llvm::errs(), DiagnosticOptions());
|
||||
new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
|
||||
|
||||
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
|
||||
DiagnosticsEngine Diags(DiagID, DiagClient);
|
||||
DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient);
|
||||
Driver TheDriver(Path.str(), llvm::sys::getDefaultTargetTriple(),
|
||||
"a.out", /*IsProduction=*/false, Diags);
|
||||
TheDriver.setTitle("clang interpreter");
|
||||
|
@ -23,6 +23,34 @@
|
||||
#include "clang-c/Platform.h"
|
||||
#include "clang-c/CXString.h"
|
||||
|
||||
/**
|
||||
* \brief The version constants for the libclang API.
|
||||
* CINDEX_VERSION_MINOR should increase when there are API additions.
|
||||
* CINDEX_VERSION_MAJOR is intended for "major" source/ABI breaking changes.
|
||||
*
|
||||
* The policy about the libclang API was always to keep it source and ABI
|
||||
* compatible, thus CINDEX_VERSION_MAJOR is expected to remain stable.
|
||||
*/
|
||||
#define CINDEX_VERSION_MAJOR 0
|
||||
#define CINDEX_VERSION_MINOR 6
|
||||
|
||||
#define CINDEX_VERSION_ENCODE(major, minor) ( \
|
||||
((major) * 10000) \
|
||||
+ ((minor) * 1))
|
||||
|
||||
#define CINDEX_VERSION CINDEX_VERSION_ENCODE( \
|
||||
CINDEX_VERSION_MAJOR, \
|
||||
CINDEX_VERSION_MINOR )
|
||||
|
||||
#define CINDEX_VERSION_STRINGIZE_(major, minor) \
|
||||
#major"."#minor
|
||||
#define CINDEX_VERSION_STRINGIZE(major, minor) \
|
||||
CINDEX_VERSION_STRINGIZE_(major, minor)
|
||||
|
||||
#define CINDEX_VERSION_STRING CINDEX_VERSION_STRINGIZE( \
|
||||
CINDEX_VERSION_MAJOR, \
|
||||
CINDEX_VERSION_MINOR)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@ -383,7 +411,7 @@ CINDEX_LINKAGE unsigned clang_equalRanges(CXSourceRange range1,
|
||||
CXSourceRange range2);
|
||||
|
||||
/**
|
||||
* \brief Returns non-zero if \arg range is null.
|
||||
* \brief Returns non-zero if \p range is null.
|
||||
*/
|
||||
CINDEX_LINKAGE int clang_Range_isNull(CXSourceRange range);
|
||||
|
||||
@ -1035,13 +1063,15 @@ enum CXTranslationUnit_Flags {
|
||||
* code-completion operations.
|
||||
*/
|
||||
CXTranslationUnit_CacheCompletionResults = 0x08,
|
||||
|
||||
/**
|
||||
* \brief DEPRECATED: Enable precompiled preambles in C++.
|
||||
* \brief Used to indicate that the translation unit will be serialized with
|
||||
* \c clang_saveTranslationUnit.
|
||||
*
|
||||
* Note: this is a *temporary* option that is available only while
|
||||
* we are testing C++ precompiled preamble support. It is deprecated.
|
||||
* This option is typically used when parsing a header with the intent of
|
||||
* producing a precompiled header.
|
||||
*/
|
||||
CXTranslationUnit_CXXPrecompiledPreamble = 0x10,
|
||||
CXTranslationUnit_ForSerialization = 0x10,
|
||||
|
||||
/**
|
||||
* \brief DEPRECATED: Enabled chained precompiled preambles in C++.
|
||||
@ -1904,9 +1934,10 @@ enum CXCursorKind {
|
||||
*/
|
||||
CXCursor_ReturnStmt = 214,
|
||||
|
||||
/** \brief A GNU inline assembly statement extension.
|
||||
/** \brief A GCC inline assembly statement extension.
|
||||
*/
|
||||
CXCursor_AsmStmt = 215,
|
||||
CXCursor_GCCAsmStmt = 215,
|
||||
CXCursor_AsmStmt = CXCursor_GCCAsmStmt,
|
||||
|
||||
/** \brief Objective-C's overall \@try-\@catch-\@finally statement.
|
||||
*/
|
||||
@ -2009,7 +2040,15 @@ enum CXCursorKind {
|
||||
CXCursor_MacroInstantiation = CXCursor_MacroExpansion,
|
||||
CXCursor_InclusionDirective = 503,
|
||||
CXCursor_FirstPreprocessing = CXCursor_PreprocessingDirective,
|
||||
CXCursor_LastPreprocessing = CXCursor_InclusionDirective
|
||||
CXCursor_LastPreprocessing = CXCursor_InclusionDirective,
|
||||
|
||||
/* Extra Declarations */
|
||||
/**
|
||||
* \brief A module import declaration.
|
||||
*/
|
||||
CXCursor_ModuleImportDecl = 600,
|
||||
CXCursor_FirstExtraDecl = CXCursor_ModuleImportDecl,
|
||||
CXCursor_LastExtraDecl = CXCursor_ModuleImportDecl
|
||||
};
|
||||
|
||||
/**
|
||||
@ -2040,7 +2079,8 @@ typedef struct {
|
||||
* \brief A comment AST node.
|
||||
*/
|
||||
typedef struct {
|
||||
const void *Data;
|
||||
const void *ASTNode;
|
||||
CXTranslationUnit TranslationUnit;
|
||||
} CXComment;
|
||||
|
||||
/**
|
||||
@ -2068,9 +2108,9 @@ CINDEX_LINKAGE CXCursor clang_getTranslationUnitCursor(CXTranslationUnit);
|
||||
CINDEX_LINKAGE unsigned clang_equalCursors(CXCursor, CXCursor);
|
||||
|
||||
/**
|
||||
* \brief Returns non-zero if \arg cursor is null.
|
||||
* \brief Returns non-zero if \p cursor is null.
|
||||
*/
|
||||
CINDEX_LINKAGE int clang_Cursor_isNull(CXCursor);
|
||||
CINDEX_LINKAGE int clang_Cursor_isNull(CXCursor cursor);
|
||||
|
||||
/**
|
||||
* \brief Compute a hash value for the given cursor.
|
||||
@ -2585,6 +2625,7 @@ enum CXCallingConv {
|
||||
CXCallingConv_X86Pascal = 5,
|
||||
CXCallingConv_AAPCS = 6,
|
||||
CXCallingConv_AAPCS_VFP = 7,
|
||||
CXCallingConv_PnaclCall = 8,
|
||||
|
||||
CXCallingConv_Invalid = 100,
|
||||
CXCallingConv_Unexposed = 200
|
||||
@ -3163,6 +3204,12 @@ CINDEX_LINKAGE int clang_Cursor_getObjCSelectorIndex(CXCursor);
|
||||
*/
|
||||
CINDEX_LINKAGE int clang_Cursor_isDynamicCall(CXCursor C);
|
||||
|
||||
/**
|
||||
* \brief Given a cursor pointing to an ObjC message, returns the CXType of the
|
||||
* receiver.
|
||||
*/
|
||||
CINDEX_LINKAGE CXType clang_Cursor_getReceiverType(CXCursor C);
|
||||
|
||||
/**
|
||||
* \brief Given a cursor that represents a declaration, return the associated
|
||||
* comment's source range. The range may include multiple consecutive comments
|
||||
@ -3190,6 +3237,65 @@ CINDEX_LINKAGE CXString clang_Cursor_getBriefCommentText(CXCursor C);
|
||||
*/
|
||||
CINDEX_LINKAGE CXComment clang_Cursor_getParsedComment(CXCursor C);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* \defgroup CINDEX_MODULE Module introspection
|
||||
*
|
||||
* The functions in this group provide access to information about modules.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
typedef void *CXModule;
|
||||
|
||||
/**
|
||||
* \brief Given a CXCursor_ModuleImportDecl cursor, return the associated module.
|
||||
*/
|
||||
CINDEX_LINKAGE CXModule clang_Cursor_getModule(CXCursor C);
|
||||
|
||||
/**
|
||||
* \param Module a module object.
|
||||
*
|
||||
* \returns the parent of a sub-module or NULL if the given module is top-level,
|
||||
* e.g. for 'std.vector' it will return the 'std' module.
|
||||
*/
|
||||
CINDEX_LINKAGE CXModule clang_Module_getParent(CXModule Module);
|
||||
|
||||
/**
|
||||
* \param Module a module object.
|
||||
*
|
||||
* \returns the name of the module, e.g. for the 'std.vector' sub-module it
|
||||
* will return "vector".
|
||||
*/
|
||||
CINDEX_LINKAGE CXString clang_Module_getName(CXModule Module);
|
||||
|
||||
/**
|
||||
* \param Module a module object.
|
||||
*
|
||||
* \returns the full name of the module, e.g. "std.vector".
|
||||
*/
|
||||
CINDEX_LINKAGE CXString clang_Module_getFullName(CXModule Module);
|
||||
|
||||
/**
|
||||
* \param Module a module object.
|
||||
*
|
||||
* \returns the number of top level headers associated with this module.
|
||||
*/
|
||||
CINDEX_LINKAGE unsigned clang_Module_getNumTopLevelHeaders(CXModule Module);
|
||||
|
||||
/**
|
||||
* \param Module a module object.
|
||||
*
|
||||
* \param Index top level header index (zero-based).
|
||||
*
|
||||
* \returns the specified top level header associated with the module.
|
||||
*/
|
||||
CINDEX_LINKAGE
|
||||
CXFile clang_Module_getTopLevelHeader(CXModule Module, unsigned Index);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
@ -3272,7 +3378,7 @@ enum CXCommentKind {
|
||||
* \brief A \\param or \\arg command that describes the function parameter
|
||||
* (name, passing direction, description).
|
||||
*
|
||||
* \brief For example: \\param [in] ParamName description.
|
||||
* For example: \\param [in] ParamName description.
|
||||
*/
|
||||
CXComment_ParamCommand = 7,
|
||||
|
||||
@ -3280,7 +3386,7 @@ enum CXCommentKind {
|
||||
* \brief A \\tparam command that describes a template parameter (name and
|
||||
* description).
|
||||
*
|
||||
* \brief For example: \\tparam T description.
|
||||
* For example: \\tparam T description.
|
||||
*/
|
||||
CXComment_TParamCommand = 8,
|
||||
|
||||
@ -3379,7 +3485,7 @@ CINDEX_LINKAGE unsigned clang_Comment_getNumChildren(CXComment Comment);
|
||||
/**
|
||||
* \param Comment AST node of any kind.
|
||||
*
|
||||
* \param ArgIdx argument index (zero-based).
|
||||
* \param ChildIdx child index (zero-based).
|
||||
*
|
||||
* \returns the specified child of the AST node.
|
||||
*/
|
||||
@ -3692,14 +3798,11 @@ CINDEX_LINKAGE CXString clang_FullComment_getAsHTML(CXComment Comment);
|
||||
* A Relax NG schema for the XML can be found in comment-xml-schema.rng file
|
||||
* inside clang source tree.
|
||||
*
|
||||
* \param TU the translation unit \c Comment belongs to.
|
||||
*
|
||||
* \param Comment a \c CXComment_FullComment AST node.
|
||||
*
|
||||
* \returns string containing an XML document.
|
||||
*/
|
||||
CINDEX_LINKAGE CXString clang_FullComment_getAsXML(CXTranslationUnit TU,
|
||||
CXComment Comment);
|
||||
CINDEX_LINKAGE CXString clang_FullComment_getAsXML(CXComment Comment);
|
||||
|
||||
/**
|
||||
* @}
|
||||
@ -4323,8 +4426,7 @@ clang_getCompletionAnnotation(CXCompletionString completion_string,
|
||||
* \param completion_string The code completion string whose parent is
|
||||
* being queried.
|
||||
*
|
||||
* \param kind If non-NULL, will be set to the kind of the parent context,
|
||||
* or CXCursor_NotImplemented if there is no context.
|
||||
* \param kind DEPRECATED: always set to CXCursor_NotImplemented if non-NULL.
|
||||
*
|
||||
* \returns The name of the completion parent, e.g., "NSObject" if
|
||||
* the completion string represents a method in the NSObject class.
|
||||
@ -4917,22 +5019,35 @@ typedef struct {
|
||||
CXFile file;
|
||||
int isImport;
|
||||
int isAngled;
|
||||
/**
|
||||
* \brief Non-zero if the directive was automatically turned into a module
|
||||
* import.
|
||||
*/
|
||||
int isModuleImport;
|
||||
} CXIdxIncludedFileInfo;
|
||||
|
||||
/**
|
||||
* \brief Data for IndexerCallbacks#importedASTFile.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* \brief Top level AST file containing the imported PCH, module or submodule.
|
||||
*/
|
||||
CXFile file;
|
||||
/**
|
||||
* \brief Location where the file is imported. It is useful mostly for
|
||||
* modules.
|
||||
* \brief The imported module or NULL if the AST file is a PCH.
|
||||
*/
|
||||
CXModule module;
|
||||
/**
|
||||
* \brief Location where the file is imported. Applicable only for modules.
|
||||
*/
|
||||
CXIdxLoc loc;
|
||||
/**
|
||||
* \brief Non-zero if the AST file is a module otherwise it's a PCH.
|
||||
* \brief Non-zero if an inclusion directive was automatically turned into
|
||||
* a module import. Applicable only for modules.
|
||||
*/
|
||||
int isModule;
|
||||
int isImplicit;
|
||||
|
||||
} CXIdxImportedASTFileInfo;
|
||||
|
||||
typedef enum {
|
||||
@ -4965,7 +5080,8 @@ typedef enum {
|
||||
CXIdxEntity_CXXConstructor = 22,
|
||||
CXIdxEntity_CXXDestructor = 23,
|
||||
CXIdxEntity_CXXConversionFunction = 24,
|
||||
CXIdxEntity_CXXTypeAlias = 25
|
||||
CXIdxEntity_CXXTypeAlias = 25,
|
||||
CXIdxEntity_CXXInterface = 26
|
||||
|
||||
} CXIdxEntityKind;
|
||||
|
||||
@ -5183,8 +5299,8 @@ typedef struct {
|
||||
*
|
||||
* AST files will not get indexed (there will not be callbacks to index all
|
||||
* the entities in an AST file). The recommended action is that, if the AST
|
||||
* file is not already indexed, to block further indexing and initiate a new
|
||||
* indexing job specific to the AST file.
|
||||
* file is not already indexed, to initiate a new indexing job specific to
|
||||
* the AST file.
|
||||
*/
|
||||
CXIdxClientASTFile (*importedASTFile)(CXClientData client_data,
|
||||
const CXIdxImportedASTFileInfo *);
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
#include "clang/ARCMigrate/FileRemapper.h"
|
||||
#include "clang/Frontend/CompilerInvocation.h"
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
|
||||
namespace clang {
|
||||
class ASTContext;
|
||||
@ -51,7 +52,7 @@ bool applyTransformations(CompilerInvocation &origCI,
|
||||
DiagnosticConsumer *DiagClient);
|
||||
|
||||
/// \brief Applies automatic modifications and produces temporary files
|
||||
/// and metadata into the \arg outputDir path.
|
||||
/// and metadata into the \p outputDir path.
|
||||
///
|
||||
/// \param emitPremigrationARCErrors if true all ARC errors will get emitted
|
||||
/// even if the migrator can fix them, but the function will still return false
|
||||
@ -68,7 +69,7 @@ bool migrateWithTemporaryFiles(CompilerInvocation &origCI,
|
||||
bool emitPremigrationARCErrors,
|
||||
StringRef plistOut);
|
||||
|
||||
/// \brief Get the set of file remappings from the \arg outputDir path that
|
||||
/// \brief Get the set of file remappings from the \p outputDir path that
|
||||
/// migrateWithTemporaryFiles produced.
|
||||
///
|
||||
/// \returns false if no error is produced, true otherwise.
|
||||
|
@ -19,12 +19,14 @@ namespace clang {
|
||||
class CXXRecordDecl;
|
||||
class DeclGroupRef;
|
||||
class HandleTagDeclDefinition;
|
||||
class PPMutationListener;
|
||||
class ASTMutationListener;
|
||||
class ASTDeserializationListener; // layering violation because void* is ugly
|
||||
class SemaConsumer; // layering violation required for safe SemaConsumer
|
||||
class TagDecl;
|
||||
class VarDecl;
|
||||
class FunctionDecl;
|
||||
class ImportDecl;
|
||||
|
||||
/// ASTConsumer - This is an abstract interface that should be implemented by
|
||||
/// clients that read ASTs. This abstraction layer allows the client to be
|
||||
@ -79,6 +81,11 @@ class ASTConsumer {
|
||||
/// The default implementation ignored them.
|
||||
virtual void HandleTopLevelDeclInObjCContainer(DeclGroupRef D);
|
||||
|
||||
/// \brief Handle an ImportDecl that was implicitly created due to an
|
||||
/// inclusion directive.
|
||||
/// The default implementation passes it to HandleTopLevelDecl.
|
||||
virtual void HandleImplicitImportDecl(ImportDecl *D);
|
||||
|
||||
/// CompleteTentativeDefinition - Callback invoked at the end of a translation
|
||||
/// unit to notify the consumer that the given tentative definition should be
|
||||
/// completed.
|
||||
@ -105,6 +112,11 @@ class ASTConsumer {
|
||||
/// it was actually used.
|
||||
virtual void HandleVTable(CXXRecordDecl *RD, bool DefinitionRequired) {}
|
||||
|
||||
/// \brief If the consumer is interested in preprocessor entities getting
|
||||
/// modified after their initial creation, it should return a pointer to
|
||||
/// a PPMutationListener here.
|
||||
virtual PPMutationListener *GetPPMutationListener() { return 0; }
|
||||
|
||||
/// \brief If the consumer is interested in entities getting modified after
|
||||
/// their initial creation, it should return a pointer to
|
||||
/// an ASTMutationListener here.
|
||||
@ -118,9 +130,6 @@ class ASTConsumer {
|
||||
|
||||
/// PrintStats - If desired, print any statistics.
|
||||
virtual void PrintStats() {}
|
||||
|
||||
// Support isa/cast/dyn_cast
|
||||
static bool classof(const ASTConsumer *) { return true; }
|
||||
};
|
||||
|
||||
} // end namespace clang.
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -13,6 +13,8 @@
|
||||
#ifndef LLVM_CLANG_AST_ASTMUTATIONLISTENER_H
|
||||
#define LLVM_CLANG_AST_ASTMUTATIONLISTENER_H
|
||||
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
|
||||
namespace clang {
|
||||
class Decl;
|
||||
class DeclContext;
|
||||
|
@ -107,9 +107,6 @@ class Attr {
|
||||
// Pretty print this attribute.
|
||||
virtual void printPretty(llvm::raw_ostream &OS,
|
||||
const PrintingPolicy &Policy) const = 0;
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *) { return true; }
|
||||
};
|
||||
|
||||
class InheritableAttr : public Attr {
|
||||
@ -125,7 +122,6 @@ class InheritableAttr : public Attr {
|
||||
static bool classof(const Attr *A) {
|
||||
return A->getKind() <= attr::LAST_INHERITABLE;
|
||||
}
|
||||
static bool classof(const InheritableAttr *) { return true; }
|
||||
};
|
||||
|
||||
class InheritableParamAttr : public InheritableAttr {
|
||||
@ -139,7 +135,6 @@ class InheritableParamAttr : public InheritableAttr {
|
||||
static bool classof(const Attr *A) {
|
||||
return A->getKind() <= attr::LAST_INHERITABLE_PARAM;
|
||||
}
|
||||
static bool classof(const InheritableParamAttr *) { return true; }
|
||||
};
|
||||
|
||||
#include "clang/AST/Attrs.inc"
|
||||
|
@ -206,6 +206,8 @@ PLACEHOLDER_TYPE(PseudoObject, PseudoObjectTy)
|
||||
// unknown type, most notably explicit casts.
|
||||
PLACEHOLDER_TYPE(UnknownAny, UnknownAnyTy)
|
||||
|
||||
PLACEHOLDER_TYPE(BuiltinFn, BuiltinFnTy)
|
||||
|
||||
// The type of a cast which, in ARC, would normally require a
|
||||
// __bridge, but which might be okay depending on the immediate
|
||||
// context.
|
||||
|
@ -20,3 +20,15 @@ clang_tablegen(CommentNodes.inc -gen-clang-comment-nodes
|
||||
SOURCE ../Basic/CommentNodes.td
|
||||
TARGET ClangCommentNodes)
|
||||
|
||||
clang_tablegen(CommentHTMLTags.inc -gen-clang-comment-html-tags
|
||||
SOURCE CommentHTMLTags.td
|
||||
TARGET ClangCommentHTMLTags)
|
||||
|
||||
clang_tablegen(CommentHTMLTagsProperties.inc -gen-clang-comment-html-tags-properties
|
||||
SOURCE CommentHTMLTags.td
|
||||
TARGET ClangCommentHTMLTagsProperties)
|
||||
|
||||
clang_tablegen(CommentCommandInfo.inc -gen-clang-comment-command-info
|
||||
SOURCE CommentCommands.td
|
||||
TARGET ClangCommentCommandInfo)
|
||||
|
||||
|
@ -19,7 +19,7 @@
|
||||
#include "clang/AST/DeclCXX.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/AST/TypeOrdering.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/MapVector.h"
|
||||
#include "llvm/ADT/SmallSet.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include <list>
|
||||
@ -271,15 +271,14 @@ struct UniqueVirtualMethod {
|
||||
/// pair is the virtual method that overrides it (including the
|
||||
/// subobject in which that virtual function occurs).
|
||||
class OverridingMethods {
|
||||
llvm::DenseMap<unsigned, SmallVector<UniqueVirtualMethod, 4> >
|
||||
Overrides;
|
||||
typedef SmallVector<UniqueVirtualMethod, 4> ValuesT;
|
||||
typedef llvm::MapVector<unsigned, ValuesT> MapType;
|
||||
MapType Overrides;
|
||||
|
||||
public:
|
||||
// Iterate over the set of subobjects that have overriding methods.
|
||||
typedef llvm::DenseMap<unsigned, SmallVector<UniqueVirtualMethod, 4> >
|
||||
::iterator iterator;
|
||||
typedef llvm::DenseMap<unsigned, SmallVector<UniqueVirtualMethod, 4> >
|
||||
::const_iterator const_iterator;
|
||||
typedef MapType::iterator iterator;
|
||||
typedef MapType::const_iterator const_iterator;
|
||||
iterator begin() { return Overrides.begin(); }
|
||||
const_iterator begin() const { return Overrides.begin(); }
|
||||
iterator end() { return Overrides.end(); }
|
||||
@ -357,8 +356,8 @@ class OverridingMethods {
|
||||
/// 0 represents the virtua base class subobject of that type, while
|
||||
/// subobject numbers greater than 0 refer to non-virtual base class
|
||||
/// subobjects of that type.
|
||||
class CXXFinalOverriderMap
|
||||
: public llvm::DenseMap<const CXXMethodDecl *, OverridingMethods> { };
|
||||
class CXXFinalOverriderMap
|
||||
: public llvm::MapVector<const CXXMethodDecl *, OverridingMethods> { };
|
||||
|
||||
/// \brief A set of all the primary bases for a class.
|
||||
class CXXIndirectPrimaryBaseSet
|
||||
|
@ -276,6 +276,7 @@ class CanProxyBase {
|
||||
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, isInterfaceType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isStructureOrClassType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isUnionType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isComplexIntegerType)
|
||||
|
@ -164,8 +164,8 @@ namespace clang {
|
||||
QuantityType getQuantity() const { return Quantity; }
|
||||
|
||||
/// RoundUpToAlignment - Returns the next integer (mod 2**64) that is
|
||||
/// greater than or equal to this quantity and is a multiple of \arg
|
||||
/// Align. Align must be non-zero.
|
||||
/// greater than or equal to this quantity and is a multiple of \p Align.
|
||||
/// Align must be non-zero.
|
||||
CharUnits RoundUpToAlignment(const CharUnits &Align) {
|
||||
return CharUnits(llvm::RoundUpToAlignment(Quantity,
|
||||
Align.Quantity));
|
||||
|
@ -16,6 +16,8 @@
|
||||
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/AST/CommentCommandTraits.h"
|
||||
#include "clang/AST/DeclObjC.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
|
||||
@ -25,7 +27,7 @@ class ParmVarDecl;
|
||||
class TemplateParameterList;
|
||||
|
||||
namespace comments {
|
||||
|
||||
class FullComment;
|
||||
/// Any part of the comment.
|
||||
/// Abstract class.
|
||||
class Comment {
|
||||
@ -74,8 +76,9 @@ class Comment {
|
||||
unsigned : NumInlineContentCommentBits;
|
||||
|
||||
unsigned RenderKind : 2;
|
||||
unsigned CommandID : 8;
|
||||
};
|
||||
enum { NumInlineCommandCommentBits = NumInlineContentCommentBits + 1 };
|
||||
enum { NumInlineCommandCommentBits = NumInlineContentCommentBits + 10 };
|
||||
|
||||
class HTMLStartTagCommentBitfields {
|
||||
friend class HTMLStartTagComment;
|
||||
@ -101,10 +104,19 @@ class Comment {
|
||||
};
|
||||
enum { NumParagraphCommentBits = NumCommentBits + 2 };
|
||||
|
||||
class BlockCommandCommentBitfields {
|
||||
friend class BlockCommandComment;
|
||||
|
||||
unsigned : NumCommentBits;
|
||||
|
||||
unsigned CommandID : 8;
|
||||
};
|
||||
enum { NumBlockCommandCommentBits = NumCommentBits + 8 };
|
||||
|
||||
class ParamCommandCommentBitfields {
|
||||
friend class ParamCommandComment;
|
||||
|
||||
unsigned : NumCommentBits;
|
||||
unsigned : NumBlockCommandCommentBits;
|
||||
|
||||
/// Parameter passing direction, see ParamCommandComment::PassDirection.
|
||||
unsigned Direction : 2;
|
||||
@ -112,7 +124,7 @@ class Comment {
|
||||
/// True if direction was specified explicitly in the comment.
|
||||
unsigned IsDirectionExplicit : 1;
|
||||
};
|
||||
enum { NumParamCommandCommentBits = 11 };
|
||||
enum { NumParamCommandCommentBits = NumBlockCommandCommentBits + 3 };
|
||||
|
||||
union {
|
||||
CommentBitfields CommentBits;
|
||||
@ -121,6 +133,7 @@ class Comment {
|
||||
InlineCommandCommentBitfields InlineCommandCommentBits;
|
||||
HTMLStartTagCommentBitfields HTMLStartTagCommentBits;
|
||||
ParagraphCommentBitfields ParagraphCommentBits;
|
||||
BlockCommandCommentBitfields BlockCommandCommentBits;
|
||||
ParamCommandCommentBitfields ParamCommandCommentBits;
|
||||
};
|
||||
|
||||
@ -158,10 +171,9 @@ class Comment {
|
||||
const char *getCommentKindName() const;
|
||||
|
||||
LLVM_ATTRIBUTE_USED void dump() const;
|
||||
LLVM_ATTRIBUTE_USED void dump(SourceManager &SM) const;
|
||||
void dump(llvm::raw_ostream &OS, SourceManager *SM) const;
|
||||
|
||||
static bool classof(const Comment *) { return true; }
|
||||
LLVM_ATTRIBUTE_USED void dump(const ASTContext &Context) const;
|
||||
void dump(llvm::raw_ostream &OS, const CommandTraits *Traits,
|
||||
const SourceManager *SM) const;
|
||||
|
||||
SourceRange getSourceRange() const LLVM_READONLY { return Range; }
|
||||
|
||||
@ -204,8 +216,6 @@ class InlineContentComment : public Comment {
|
||||
C->getCommentKind() <= LastInlineContentCommentConstant;
|
||||
}
|
||||
|
||||
static bool classof(const InlineContentComment *) { return true; }
|
||||
|
||||
void addTrailingNewline() {
|
||||
InlineContentCommentBits.HasTrailingNewline = 1;
|
||||
}
|
||||
@ -232,8 +242,6 @@ class TextComment : public InlineContentComment {
|
||||
return C->getCommentKind() == TextCommentKind;
|
||||
}
|
||||
|
||||
static bool classof(const TextComment *) { return true; }
|
||||
|
||||
child_iterator child_begin() const { return NULL; }
|
||||
|
||||
child_iterator child_end() const { return NULL; }
|
||||
@ -273,35 +281,35 @@ class InlineCommandComment : public InlineContentComment {
|
||||
};
|
||||
|
||||
protected:
|
||||
/// Command name.
|
||||
StringRef Name;
|
||||
|
||||
/// Command arguments.
|
||||
llvm::ArrayRef<Argument> Args;
|
||||
|
||||
public:
|
||||
InlineCommandComment(SourceLocation LocBegin,
|
||||
SourceLocation LocEnd,
|
||||
StringRef Name,
|
||||
unsigned CommandID,
|
||||
RenderKind RK,
|
||||
llvm::ArrayRef<Argument> Args) :
|
||||
InlineContentComment(InlineCommandCommentKind, LocBegin, LocEnd),
|
||||
Name(Name), Args(Args) {
|
||||
Args(Args) {
|
||||
InlineCommandCommentBits.RenderKind = RK;
|
||||
InlineCommandCommentBits.CommandID = CommandID;
|
||||
}
|
||||
|
||||
static bool classof(const Comment *C) {
|
||||
return C->getCommentKind() == InlineCommandCommentKind;
|
||||
}
|
||||
|
||||
static bool classof(const InlineCommandComment *) { return true; }
|
||||
|
||||
child_iterator child_begin() const { return NULL; }
|
||||
|
||||
child_iterator child_end() const { return NULL; }
|
||||
|
||||
StringRef getCommandName() const {
|
||||
return Name;
|
||||
unsigned getCommandID() const {
|
||||
return InlineCommandCommentBits.CommandID;
|
||||
}
|
||||
|
||||
StringRef getCommandName(const CommandTraits &Traits) const {
|
||||
return Traits.getCommandInfo(getCommandID())->Name;
|
||||
}
|
||||
|
||||
SourceRange getCommandNameRange() const {
|
||||
@ -352,8 +360,6 @@ class HTMLTagComment : public InlineContentComment {
|
||||
C->getCommentKind() <= LastHTMLTagCommentConstant;
|
||||
}
|
||||
|
||||
static bool classof(const HTMLTagComment *) { return true; }
|
||||
|
||||
StringRef getTagName() const LLVM_READONLY { return TagName; }
|
||||
|
||||
SourceRange getTagNameSourceRange() const LLVM_READONLY {
|
||||
@ -419,8 +425,6 @@ class HTMLStartTagComment : public HTMLTagComment {
|
||||
return C->getCommentKind() == HTMLStartTagCommentKind;
|
||||
}
|
||||
|
||||
static bool classof(const HTMLStartTagComment *) { return true; }
|
||||
|
||||
child_iterator child_begin() const { return NULL; }
|
||||
|
||||
child_iterator child_end() const { return NULL; }
|
||||
@ -476,8 +480,6 @@ class HTMLEndTagComment : public HTMLTagComment {
|
||||
return C->getCommentKind() == HTMLEndTagCommentKind;
|
||||
}
|
||||
|
||||
static bool classof(const HTMLEndTagComment *) { return true; }
|
||||
|
||||
child_iterator child_begin() const { return NULL; }
|
||||
|
||||
child_iterator child_end() const { return NULL; }
|
||||
@ -498,8 +500,6 @@ class BlockContentComment : public Comment {
|
||||
return C->getCommentKind() >= FirstBlockContentCommentConstant &&
|
||||
C->getCommentKind() <= LastBlockContentCommentConstant;
|
||||
}
|
||||
|
||||
static bool classof(const BlockContentComment *) { return true; }
|
||||
};
|
||||
|
||||
/// A single paragraph that contains inline content.
|
||||
@ -529,8 +529,6 @@ class ParagraphComment : public BlockContentComment {
|
||||
return C->getCommentKind() == ParagraphCommentKind;
|
||||
}
|
||||
|
||||
static bool classof(const ParagraphComment *) { return true; }
|
||||
|
||||
child_iterator child_begin() const {
|
||||
return reinterpret_cast<child_iterator>(Content.begin());
|
||||
}
|
||||
@ -566,9 +564,6 @@ class BlockCommandComment : public BlockContentComment {
|
||||
};
|
||||
|
||||
protected:
|
||||
/// Command name.
|
||||
StringRef Name;
|
||||
|
||||
/// Word-like arguments.
|
||||
llvm::ArrayRef<Argument> Args;
|
||||
|
||||
@ -578,21 +573,21 @@ class BlockCommandComment : public BlockContentComment {
|
||||
BlockCommandComment(CommentKind K,
|
||||
SourceLocation LocBegin,
|
||||
SourceLocation LocEnd,
|
||||
StringRef Name) :
|
||||
unsigned CommandID) :
|
||||
BlockContentComment(K, LocBegin, LocEnd),
|
||||
Name(Name),
|
||||
Paragraph(NULL) {
|
||||
setLocation(getCommandNameRange().getBegin());
|
||||
setLocation(getCommandNameBeginLoc());
|
||||
BlockCommandCommentBits.CommandID = CommandID;
|
||||
}
|
||||
|
||||
public:
|
||||
BlockCommandComment(SourceLocation LocBegin,
|
||||
SourceLocation LocEnd,
|
||||
StringRef Name) :
|
||||
unsigned CommandID) :
|
||||
BlockContentComment(BlockCommandCommentKind, LocBegin, LocEnd),
|
||||
Name(Name),
|
||||
Paragraph(NULL) {
|
||||
setLocation(getCommandNameRange().getBegin());
|
||||
setLocation(getCommandNameBeginLoc());
|
||||
BlockCommandCommentBits.CommandID = CommandID;
|
||||
}
|
||||
|
||||
static bool classof(const Comment *C) {
|
||||
@ -600,8 +595,6 @@ class BlockCommandComment : public BlockContentComment {
|
||||
C->getCommentKind() <= LastBlockCommandCommentConstant;
|
||||
}
|
||||
|
||||
static bool classof(const BlockCommandComment *) { return true; }
|
||||
|
||||
child_iterator child_begin() const {
|
||||
return reinterpret_cast<child_iterator>(&Paragraph);
|
||||
}
|
||||
@ -610,12 +603,21 @@ class BlockCommandComment : public BlockContentComment {
|
||||
return reinterpret_cast<child_iterator>(&Paragraph + 1);
|
||||
}
|
||||
|
||||
StringRef getCommandName() const {
|
||||
return Name;
|
||||
unsigned getCommandID() const {
|
||||
return BlockCommandCommentBits.CommandID;
|
||||
}
|
||||
|
||||
SourceRange getCommandNameRange() const {
|
||||
return SourceRange(getLocStart().getLocWithOffset(1),
|
||||
StringRef getCommandName(const CommandTraits &Traits) const {
|
||||
return Traits.getCommandInfo(getCommandID())->Name;
|
||||
}
|
||||
|
||||
SourceLocation getCommandNameBeginLoc() const {
|
||||
return getLocStart().getLocWithOffset(1);
|
||||
}
|
||||
|
||||
SourceRange getCommandNameRange(const CommandTraits &Traits) const {
|
||||
StringRef Name = getCommandName(Traits);
|
||||
return SourceRange(getCommandNameBeginLoc(),
|
||||
getLocStart().getLocWithOffset(1 + Name.size()));
|
||||
}
|
||||
|
||||
@ -667,8 +669,9 @@ class ParamCommandComment : public BlockCommandComment {
|
||||
|
||||
ParamCommandComment(SourceLocation LocBegin,
|
||||
SourceLocation LocEnd,
|
||||
StringRef Name) :
|
||||
BlockCommandComment(ParamCommandCommentKind, LocBegin, LocEnd, Name),
|
||||
unsigned CommandID) :
|
||||
BlockCommandComment(ParamCommandCommentKind, LocBegin, LocEnd,
|
||||
CommandID),
|
||||
ParamIndex(InvalidParamIndex) {
|
||||
ParamCommandCommentBits.Direction = In;
|
||||
ParamCommandCommentBits.IsDirectionExplicit = false;
|
||||
@ -678,8 +681,6 @@ class ParamCommandComment : public BlockCommandComment {
|
||||
return C->getCommentKind() == ParamCommandCommentKind;
|
||||
}
|
||||
|
||||
static bool classof(const ParamCommandComment *) { return true; }
|
||||
|
||||
enum PassDirection {
|
||||
In,
|
||||
Out,
|
||||
@ -705,7 +706,9 @@ class ParamCommandComment : public BlockCommandComment {
|
||||
return getNumArgs() > 0;
|
||||
}
|
||||
|
||||
StringRef getParamName() const {
|
||||
StringRef getParamName(const FullComment *FC) const;
|
||||
|
||||
StringRef getParamNameAsWritten() const {
|
||||
return Args[0].Text;
|
||||
}
|
||||
|
||||
@ -748,21 +751,21 @@ class TParamCommandComment : public BlockCommandComment {
|
||||
public:
|
||||
TParamCommandComment(SourceLocation LocBegin,
|
||||
SourceLocation LocEnd,
|
||||
StringRef Name) :
|
||||
BlockCommandComment(TParamCommandCommentKind, LocBegin, LocEnd, Name)
|
||||
unsigned CommandID) :
|
||||
BlockCommandComment(TParamCommandCommentKind, LocBegin, LocEnd, CommandID)
|
||||
{ }
|
||||
|
||||
static bool classof(const Comment *C) {
|
||||
return C->getCommentKind() == TParamCommandCommentKind;
|
||||
}
|
||||
|
||||
static bool classof(const TParamCommandComment *) { return true; }
|
||||
|
||||
bool hasParamName() const {
|
||||
return getNumArgs() > 0;
|
||||
}
|
||||
|
||||
StringRef getParamName() const {
|
||||
StringRef getParamName(const FullComment *FC) const;
|
||||
|
||||
StringRef getParamNameAsWritten() const {
|
||||
return Args[0].Text;
|
||||
}
|
||||
|
||||
@ -807,8 +810,6 @@ class VerbatimBlockLineComment : public Comment {
|
||||
return C->getCommentKind() == VerbatimBlockLineCommentKind;
|
||||
}
|
||||
|
||||
static bool classof(const VerbatimBlockLineComment *) { return true; }
|
||||
|
||||
child_iterator child_begin() const { return NULL; }
|
||||
|
||||
child_iterator child_end() const { return NULL; }
|
||||
@ -830,17 +831,15 @@ class VerbatimBlockComment : public BlockCommandComment {
|
||||
public:
|
||||
VerbatimBlockComment(SourceLocation LocBegin,
|
||||
SourceLocation LocEnd,
|
||||
StringRef Name) :
|
||||
unsigned CommandID) :
|
||||
BlockCommandComment(VerbatimBlockCommentKind,
|
||||
LocBegin, LocEnd, Name)
|
||||
LocBegin, LocEnd, CommandID)
|
||||
{ }
|
||||
|
||||
static bool classof(const Comment *C) {
|
||||
return C->getCommentKind() == VerbatimBlockCommentKind;
|
||||
}
|
||||
|
||||
static bool classof(const VerbatimBlockComment *) { return true; }
|
||||
|
||||
child_iterator child_begin() const {
|
||||
return reinterpret_cast<child_iterator>(Lines.begin());
|
||||
}
|
||||
@ -882,12 +881,12 @@ class VerbatimLineComment : public BlockCommandComment {
|
||||
public:
|
||||
VerbatimLineComment(SourceLocation LocBegin,
|
||||
SourceLocation LocEnd,
|
||||
StringRef Name,
|
||||
unsigned CommandID,
|
||||
SourceLocation TextBegin,
|
||||
StringRef Text) :
|
||||
BlockCommandComment(VerbatimLineCommentKind,
|
||||
LocBegin, LocEnd,
|
||||
Name),
|
||||
CommandID),
|
||||
Text(Text),
|
||||
TextBegin(TextBegin)
|
||||
{ }
|
||||
@ -896,8 +895,6 @@ class VerbatimLineComment : public BlockCommandComment {
|
||||
return C->getCommentKind() == VerbatimLineCommentKind;
|
||||
}
|
||||
|
||||
static bool classof(const VerbatimLineComment *) { return true; }
|
||||
|
||||
child_iterator child_begin() const { return NULL; }
|
||||
|
||||
child_iterator child_end() const { return NULL; }
|
||||
@ -913,23 +910,34 @@ class VerbatimLineComment : public BlockCommandComment {
|
||||
|
||||
/// Information about the declaration, useful to clients of FullComment.
|
||||
struct DeclInfo {
|
||||
/// Declaration the comment is attached to. Should not be NULL.
|
||||
const Decl *ThisDecl;
|
||||
|
||||
/// Parameters that can be referenced by \\param if \c ThisDecl is something
|
||||
/// Declaration the comment is actually attached to (in the source).
|
||||
/// Should not be NULL.
|
||||
const Decl *CommentDecl;
|
||||
|
||||
/// CurrentDecl is the declaration with which the FullComment is associated.
|
||||
///
|
||||
/// It can be different from \c CommentDecl. It happens when we we decide
|
||||
/// that the comment originally attached to \c CommentDecl is fine for
|
||||
/// \c CurrentDecl too (for example, for a redeclaration or an overrider of
|
||||
/// \c CommentDecl).
|
||||
///
|
||||
/// The information in the DeclInfo corresponds to CurrentDecl.
|
||||
const Decl *CurrentDecl;
|
||||
|
||||
/// Parameters that can be referenced by \\param if \c CommentDecl is something
|
||||
/// that we consider a "function".
|
||||
ArrayRef<const ParmVarDecl *> ParamVars;
|
||||
|
||||
/// Function result type if \c ThisDecl is something that we consider
|
||||
/// Function result type if \c CommentDecl is something that we consider
|
||||
/// a "function".
|
||||
QualType ResultType;
|
||||
|
||||
/// Template parameters that can be referenced by \\tparam if \c ThisDecl is
|
||||
/// Template parameters that can be referenced by \\tparam if \c CommentDecl is
|
||||
/// a template (\c IsTemplateDecl or \c IsTemplatePartialSpecialization is
|
||||
/// true).
|
||||
const TemplateParameterList *TemplateParameters;
|
||||
|
||||
/// A simplified description of \c ThisDecl kind that should be good enough
|
||||
/// A simplified description of \c CommentDecl kind that should be good enough
|
||||
/// for documentation rendering purposes.
|
||||
enum DeclKind {
|
||||
/// Everything else not explicitly mentioned below.
|
||||
@ -942,7 +950,9 @@ struct DeclInfo {
|
||||
/// \li member function,
|
||||
/// \li member function template,
|
||||
/// \li member function template specialization,
|
||||
/// \li ObjC method.
|
||||
/// \li ObjC method,
|
||||
/// \li a typedef for a function pointer, member function pointer,
|
||||
/// ObjC block.
|
||||
FunctionKind,
|
||||
|
||||
/// Something that we consider a "class":
|
||||
@ -968,7 +978,7 @@ struct DeclInfo {
|
||||
EnumKind
|
||||
};
|
||||
|
||||
/// What kind of template specialization \c ThisDecl is.
|
||||
/// What kind of template specialization \c CommentDecl is.
|
||||
enum TemplateDeclKind {
|
||||
NotTemplate,
|
||||
Template,
|
||||
@ -976,24 +986,24 @@ struct DeclInfo {
|
||||
TemplatePartialSpecialization
|
||||
};
|
||||
|
||||
/// If false, only \c ThisDecl is valid.
|
||||
/// If false, only \c CommentDecl is valid.
|
||||
unsigned IsFilled : 1;
|
||||
|
||||
/// Simplified kind of \c ThisDecl, see\c DeclKind enum.
|
||||
/// Simplified kind of \c CommentDecl, see \c DeclKind enum.
|
||||
unsigned Kind : 3;
|
||||
|
||||
/// Is \c ThisDecl a template declaration.
|
||||
/// Is \c CommentDecl a template declaration.
|
||||
unsigned TemplateKind : 2;
|
||||
|
||||
/// Is \c ThisDecl an ObjCMethodDecl.
|
||||
/// Is \c CommentDecl an ObjCMethodDecl.
|
||||
unsigned IsObjCMethod : 1;
|
||||
|
||||
/// Is \c ThisDecl a non-static member function of C++ class or
|
||||
/// Is \c CommentDecl a non-static member function of C++ class or
|
||||
/// instance method of ObjC class.
|
||||
/// Can be true only if \c IsFunctionDecl is true.
|
||||
unsigned IsInstanceMethod : 1;
|
||||
|
||||
/// Is \c ThisDecl a static member function of C++ class or
|
||||
/// Is \c CommentDecl a static member function of C++ class or
|
||||
/// class method of ObjC class.
|
||||
/// Can be true only if \c IsFunctionDecl is true.
|
||||
unsigned IsClassMethod : 1;
|
||||
@ -1012,7 +1022,6 @@ struct DeclInfo {
|
||||
/// A full comment attached to a declaration, contains block content.
|
||||
class FullComment : public Comment {
|
||||
llvm::ArrayRef<BlockContentComment *> Blocks;
|
||||
|
||||
DeclInfo *ThisDeclInfo;
|
||||
|
||||
public:
|
||||
@ -1031,27 +1040,31 @@ class FullComment : public Comment {
|
||||
return C->getCommentKind() == FullCommentKind;
|
||||
}
|
||||
|
||||
static bool classof(const FullComment *) { return true; }
|
||||
|
||||
child_iterator child_begin() const {
|
||||
return reinterpret_cast<child_iterator>(Blocks.begin());
|
||||
}
|
||||
|
||||
child_iterator child_end() const {
|
||||
return reinterpret_cast<child_iterator>(Blocks.end());
|
||||
return reinterpret_cast<child_iterator>(Blocks.end());
|
||||
}
|
||||
|
||||
const Decl *getDecl() const LLVM_READONLY {
|
||||
return ThisDeclInfo->ThisDecl;
|
||||
return ThisDeclInfo->CommentDecl;
|
||||
}
|
||||
|
||||
|
||||
const DeclInfo *getDeclInfo() const LLVM_READONLY {
|
||||
if (!ThisDeclInfo->IsFilled)
|
||||
ThisDeclInfo->fill();
|
||||
return ThisDeclInfo;
|
||||
}
|
||||
|
||||
DeclInfo *getThisDeclInfo() const LLVM_READONLY {
|
||||
return ThisDeclInfo;
|
||||
}
|
||||
|
||||
llvm::ArrayRef<BlockContentComment *> getBlocks() const { return Blocks; }
|
||||
|
||||
};
|
||||
|
||||
} // end namespace comments
|
||||
} // end namespace clang
|
||||
|
||||
|
@ -44,8 +44,7 @@ class BriefParser {
|
||||
public:
|
||||
BriefParser(Lexer &L, const CommandTraits &Traits);
|
||||
|
||||
/// Return \\brief paragraph, if it exists; otherwise return the first
|
||||
/// paragraph.
|
||||
/// Return the best "brief description" we can find.
|
||||
std::string Parse();
|
||||
};
|
||||
|
||||
|
@ -19,135 +19,131 @@
|
||||
#include "clang/Basic/LLVM.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringSwitch.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
|
||||
namespace clang {
|
||||
namespace comments {
|
||||
|
||||
/// This class provides informaiton about commands that can be used
|
||||
/// in comments.
|
||||
class CommandTraits {
|
||||
public:
|
||||
CommandTraits() { }
|
||||
/// \brief Information about a single command.
|
||||
///
|
||||
/// When reordering, adding or removing members please update the corresponding
|
||||
/// TableGen backend.
|
||||
struct CommandInfo {
|
||||
unsigned getID() const {
|
||||
return ID;
|
||||
}
|
||||
|
||||
/// \brief Check if a given command is a verbatim-like block command.
|
||||
const char *Name;
|
||||
|
||||
/// Name of the command that ends the verbatim block.
|
||||
const char *EndCommandName;
|
||||
|
||||
unsigned ID : 8;
|
||||
|
||||
/// Number of word-like arguments for a given block command, except for
|
||||
/// \\param and \\tparam commands -- these have special argument parsers.
|
||||
unsigned NumArgs : 4;
|
||||
|
||||
/// True if this command is a inline command (of any kind).
|
||||
unsigned IsInlineCommand : 1;
|
||||
|
||||
/// True if this command is a block command (of any kind).
|
||||
unsigned IsBlockCommand : 1;
|
||||
|
||||
/// True if this command is introducing a brief documentation
|
||||
/// paragraph (\\brief or an alias).
|
||||
unsigned IsBriefCommand : 1;
|
||||
|
||||
/// True if this command is \\returns or an alias.
|
||||
unsigned IsReturnsCommand : 1;
|
||||
|
||||
/// True if this command is introducing documentation for a function
|
||||
/// parameter (\\param or an alias).
|
||||
unsigned IsParamCommand : 1;
|
||||
|
||||
/// True if this command is introducing documentation for
|
||||
/// a template parameter (\\tparam or an alias).
|
||||
unsigned IsTParamCommand : 1;
|
||||
|
||||
/// True if this command is \\deprecated or an alias.
|
||||
unsigned IsDeprecatedCommand : 1;
|
||||
|
||||
/// True if we don't want to warn about this command being passed an empty
|
||||
/// paragraph. Meaningful only for block commands.
|
||||
unsigned IsEmptyParagraphAllowed : 1;
|
||||
|
||||
/// \brief True if this command is a verbatim-like block command.
|
||||
///
|
||||
/// A verbatim-like block command eats every character (except line starting
|
||||
/// decorations) until matching end command is seen or comment end is hit.
|
||||
///
|
||||
/// \param StartName name of the command that starts the verbatim block.
|
||||
/// \param [out] EndName name of the command that ends the verbatim block.
|
||||
///
|
||||
/// \returns true if a given command is a verbatim block command.
|
||||
bool isVerbatimBlockCommand(StringRef StartName, StringRef &EndName) const;
|
||||
unsigned IsVerbatimBlockCommand : 1;
|
||||
|
||||
/// \brief Register a new verbatim block command.
|
||||
void addVerbatimBlockCommand(StringRef StartName, StringRef EndName);
|
||||
/// \brief True if this command is an end command for a verbatim-like block.
|
||||
unsigned IsVerbatimBlockEndCommand : 1;
|
||||
|
||||
/// \brief Check if a given command is a verbatim line command.
|
||||
/// \brief True if this command is a verbatim line command.
|
||||
///
|
||||
/// A verbatim-like line command eats everything until a newline is seen or
|
||||
/// comment end is hit.
|
||||
bool isVerbatimLineCommand(StringRef Name) const;
|
||||
unsigned IsVerbatimLineCommand : 1;
|
||||
|
||||
/// \brief Check if a given command is a command that contains a declaration
|
||||
/// for the entity being documented.
|
||||
/// \brief True if this command contains a declaration for the entity being
|
||||
/// documented.
|
||||
///
|
||||
/// For example:
|
||||
/// \code
|
||||
/// \fn void f(int a);
|
||||
/// \endcode
|
||||
bool isDeclarationCommand(StringRef Name) const;
|
||||
unsigned IsDeclarationCommand : 1;
|
||||
|
||||
/// \brief Register a new verbatim line command.
|
||||
void addVerbatimLineCommand(StringRef Name);
|
||||
|
||||
/// \brief Check if a given command is a block command (of any kind).
|
||||
bool isBlockCommand(StringRef Name) const;
|
||||
|
||||
/// \brief Check if a given command is introducing documentation for
|
||||
/// a function parameter (\\param or an alias).
|
||||
bool isParamCommand(StringRef Name) const;
|
||||
|
||||
/// \brief Check if a given command is introducing documentation for
|
||||
/// a template parameter (\\tparam or an alias).
|
||||
bool isTParamCommand(StringRef Name) const;
|
||||
|
||||
/// \brief Check if a given command is introducing a brief documentation
|
||||
/// paragraph (\\brief or an alias).
|
||||
bool isBriefCommand(StringRef Name) const;
|
||||
|
||||
/// \brief Check if a given command is \\brief or an alias.
|
||||
bool isReturnsCommand(StringRef Name) const;
|
||||
|
||||
/// \returns the number of word-like arguments for a given block command,
|
||||
/// except for \\param and \\tparam commands -- these have special argument
|
||||
/// parsers.
|
||||
unsigned getBlockCommandNumArgs(StringRef Name) const;
|
||||
|
||||
/// \brief Check if a given command is a inline command (of any kind).
|
||||
bool isInlineCommand(StringRef Name) const;
|
||||
|
||||
private:
|
||||
struct VerbatimBlockCommand {
|
||||
StringRef StartName;
|
||||
StringRef EndName;
|
||||
};
|
||||
|
||||
typedef SmallVector<VerbatimBlockCommand, 4> VerbatimBlockCommandVector;
|
||||
|
||||
/// Registered additional verbatim-like block commands.
|
||||
VerbatimBlockCommandVector VerbatimBlockCommands;
|
||||
|
||||
struct VerbatimLineCommand {
|
||||
StringRef Name;
|
||||
};
|
||||
|
||||
typedef SmallVector<VerbatimLineCommand, 4> VerbatimLineCommandVector;
|
||||
|
||||
/// Registered verbatim-like line commands.
|
||||
VerbatimLineCommandVector VerbatimLineCommands;
|
||||
/// \brief True if this command is unknown. This \c CommandInfo object was
|
||||
/// created during parsing.
|
||||
unsigned IsUnknownCommand : 1;
|
||||
};
|
||||
|
||||
inline bool CommandTraits::isBlockCommand(StringRef Name) const {
|
||||
return isBriefCommand(Name) || isReturnsCommand(Name) ||
|
||||
isParamCommand(Name) || isTParamCommand(Name) ||
|
||||
llvm::StringSwitch<bool>(Name)
|
||||
.Case("author", true)
|
||||
.Case("authors", true)
|
||||
.Case("pre", true)
|
||||
.Case("post", true)
|
||||
.Default(false);
|
||||
}
|
||||
/// This class provides information about commands that can be used
|
||||
/// in comments.
|
||||
class CommandTraits {
|
||||
public:
|
||||
CommandTraits(llvm::BumpPtrAllocator &Allocator);
|
||||
|
||||
inline bool CommandTraits::isParamCommand(StringRef Name) const {
|
||||
return Name == "param";
|
||||
}
|
||||
/// \returns a CommandInfo object for a given command name or
|
||||
/// NULL if no CommandInfo object exists for this command.
|
||||
const CommandInfo *getCommandInfoOrNULL(StringRef Name) const;
|
||||
|
||||
inline bool CommandTraits::isTParamCommand(StringRef Name) const {
|
||||
return Name == "tparam" || // Doxygen
|
||||
Name == "templatefield"; // HeaderDoc
|
||||
}
|
||||
const CommandInfo *getCommandInfo(StringRef Name) const {
|
||||
if (const CommandInfo *Info = getCommandInfoOrNULL(Name))
|
||||
return Info;
|
||||
llvm_unreachable("the command should be known");
|
||||
}
|
||||
|
||||
inline bool CommandTraits::isBriefCommand(StringRef Name) const {
|
||||
return Name == "brief" || Name == "short";
|
||||
}
|
||||
const CommandInfo *getCommandInfo(unsigned CommandID) const;
|
||||
|
||||
inline bool CommandTraits::isReturnsCommand(StringRef Name) const {
|
||||
return Name == "returns" || Name == "return" || Name == "result";
|
||||
}
|
||||
const CommandInfo *registerUnknownCommand(StringRef CommandName);
|
||||
|
||||
inline unsigned CommandTraits::getBlockCommandNumArgs(StringRef Name) const {
|
||||
return 0;
|
||||
}
|
||||
/// \returns a CommandInfo object for a given command name or
|
||||
/// NULL if \c Name is not a builtin command.
|
||||
static const CommandInfo *getBuiltinCommandInfo(StringRef Name);
|
||||
|
||||
inline bool CommandTraits::isInlineCommand(StringRef Name) const {
|
||||
return llvm::StringSwitch<bool>(Name)
|
||||
.Case("b", true)
|
||||
.Cases("c", "p", true)
|
||||
.Cases("a", "e", "em", true)
|
||||
.Default(false);
|
||||
}
|
||||
/// \returns a CommandInfo object for a given command ID or
|
||||
/// NULL if \c CommandID is not a builtin command.
|
||||
static const CommandInfo *getBuiltinCommandInfo(unsigned CommandID);
|
||||
|
||||
private:
|
||||
CommandTraits(const CommandTraits &) LLVM_DELETED_FUNCTION;
|
||||
void operator=(const CommandTraits &) LLVM_DELETED_FUNCTION;
|
||||
|
||||
const CommandInfo *getRegisteredCommandInfo(StringRef Name) const;
|
||||
const CommandInfo *getRegisteredCommandInfo(unsigned CommandID) const;
|
||||
|
||||
unsigned NextID;
|
||||
|
||||
/// Allocator for CommandInfo objects.
|
||||
llvm::BumpPtrAllocator &Allocator;
|
||||
|
||||
SmallVector<CommandInfo *, 4> RegisteredCommands;
|
||||
};
|
||||
|
||||
} // end namespace comments
|
||||
} // end namespace clang
|
||||
|
156
include/clang/AST/CommentCommands.td
Normal file
156
include/clang/AST/CommentCommands.td
Normal file
@ -0,0 +1,156 @@
|
||||
class Command<string name> {
|
||||
string Name = name;
|
||||
string EndCommandName = "";
|
||||
|
||||
int NumArgs = 0;
|
||||
|
||||
bit IsInlineCommand = 0;
|
||||
|
||||
bit IsBlockCommand = 0;
|
||||
bit IsBriefCommand = 0;
|
||||
bit IsReturnsCommand = 0;
|
||||
bit IsParamCommand = 0;
|
||||
bit IsTParamCommand = 0;
|
||||
bit IsDeprecatedCommand = 0;
|
||||
|
||||
bit IsEmptyParagraphAllowed = 0;
|
||||
|
||||
bit IsVerbatimBlockCommand = 0;
|
||||
bit IsVerbatimBlockEndCommand = 0;
|
||||
bit IsVerbatimLineCommand = 0;
|
||||
bit IsDeclarationCommand = 0;
|
||||
}
|
||||
|
||||
class InlineCommand<string name> : Command<name> {
|
||||
let IsInlineCommand = 1;
|
||||
}
|
||||
|
||||
class BlockCommand<string name> : Command<name> {
|
||||
let IsBlockCommand = 1;
|
||||
}
|
||||
|
||||
class VerbatimBlockCommand<string name> : Command<name> {
|
||||
let EndCommandName = name;
|
||||
let IsVerbatimBlockCommand = 1;
|
||||
}
|
||||
|
||||
multiclass VerbatimBlockCommand<string name, string endCommandName> {
|
||||
def Begin : Command<name> {
|
||||
let EndCommandName = endCommandName;
|
||||
let IsVerbatimBlockCommand = 1;
|
||||
}
|
||||
|
||||
def End : Command<endCommandName> {
|
||||
let IsVerbatimBlockEndCommand = 1;
|
||||
}
|
||||
}
|
||||
|
||||
class VerbatimLineCommand<string name> : Command<name> {
|
||||
let IsVerbatimLineCommand = 1;
|
||||
}
|
||||
|
||||
class DeclarationVerbatimLineCommand<string name> :
|
||||
VerbatimLineCommand<name> {
|
||||
let IsDeclarationCommand = 1;
|
||||
}
|
||||
|
||||
def B : InlineCommand<"b">;
|
||||
def C : InlineCommand<"c">;
|
||||
def P : InlineCommand<"p">;
|
||||
def A : InlineCommand<"a">;
|
||||
def E : InlineCommand<"e">;
|
||||
def Em : InlineCommand<"em">;
|
||||
|
||||
def Brief : BlockCommand<"brief"> { let IsBriefCommand = 1; }
|
||||
def Short : BlockCommand<"short"> { let IsBriefCommand = 1; }
|
||||
|
||||
def Returns : BlockCommand<"returns"> { let IsReturnsCommand = 1; }
|
||||
def Return : BlockCommand<"return"> { let IsReturnsCommand = 1; }
|
||||
def Result : BlockCommand<"result"> { let IsReturnsCommand = 1; }
|
||||
|
||||
def Param : BlockCommand<"param"> { let IsParamCommand = 1; }
|
||||
|
||||
// Doxygen
|
||||
def Tparam : BlockCommand<"tparam"> { let IsTParamCommand = 1; }
|
||||
|
||||
// HeaderDoc
|
||||
def Templatefield : BlockCommand<"templatefield"> { let IsTParamCommand = 1; }
|
||||
|
||||
def Deprecated : BlockCommand<"deprecated"> {
|
||||
let IsEmptyParagraphAllowed = 1;
|
||||
let IsDeprecatedCommand = 1;
|
||||
}
|
||||
|
||||
def Author : BlockCommand<"author">;
|
||||
def Authors : BlockCommand<"authors">;
|
||||
def Bug : BlockCommand<"bug">;
|
||||
def Copyright : BlockCommand<"copyright">;
|
||||
def Date : BlockCommand<"date">;
|
||||
def Details : BlockCommand<"details">;
|
||||
def Invariant : BlockCommand<"invariant">;
|
||||
def Note : BlockCommand<"note">;
|
||||
def Post : BlockCommand<"post">;
|
||||
def Pre : BlockCommand<"pre">;
|
||||
def Remark : BlockCommand<"remark">;
|
||||
def Remarks : BlockCommand<"remarks">;
|
||||
def Sa : BlockCommand<"sa">;
|
||||
def See : BlockCommand<"see">;
|
||||
def Since : BlockCommand<"since">;
|
||||
def Todo : BlockCommand<"todo">;
|
||||
def Version : BlockCommand<"version">;
|
||||
def Warning : BlockCommand<"warning">;
|
||||
|
||||
defm Code : VerbatimBlockCommand<"code", "endcode">;
|
||||
defm Verbatim : VerbatimBlockCommand<"verbatim", "endverbatim">;
|
||||
defm Htmlonly : VerbatimBlockCommand<"htmlonly", "endhtmlonly">;
|
||||
defm Latexonly : VerbatimBlockCommand<"latexonly", "endlatexonly">;
|
||||
defm Xmlonly : VerbatimBlockCommand<"xmlonly", "endxmlonly">;
|
||||
defm Manonly : VerbatimBlockCommand<"manonly", "endmanonly">;
|
||||
defm Rtfonly : VerbatimBlockCommand<"rtfonly", "endrtfonly">;
|
||||
|
||||
defm Dot : VerbatimBlockCommand<"dot", "enddot">;
|
||||
defm Msc : VerbatimBlockCommand<"msc", "endmsc">;
|
||||
|
||||
// These commands have special support in lexer.
|
||||
def FDollar : VerbatimBlockCommand<"f$">; // Inline LaTeX formula
|
||||
defm FBracket : VerbatimBlockCommand<"f[", "f]">; // Displayed LaTeX formula
|
||||
defm FBrace : VerbatimBlockCommand<"f{", "f}">; // LaTeX environment
|
||||
|
||||
def Defgroup : VerbatimLineCommand<"defgroup">;
|
||||
def Ingroup : VerbatimLineCommand<"ingroup">;
|
||||
def Addtogroup : VerbatimLineCommand<"addtogroup">;
|
||||
def Weakgroup : VerbatimLineCommand<"weakgroup">;
|
||||
def Name : VerbatimLineCommand<"name">;
|
||||
|
||||
def Section : VerbatimLineCommand<"section">;
|
||||
def Subsection : VerbatimLineCommand<"subsection">;
|
||||
def Subsubsection : VerbatimLineCommand<"subsubsection">;
|
||||
def Paragraph : VerbatimLineCommand<"paragraph">;
|
||||
|
||||
def Mainpage : VerbatimLineCommand<"mainpage">;
|
||||
def Subpage : VerbatimLineCommand<"subpage">;
|
||||
def Ref : VerbatimLineCommand<"ref">;
|
||||
|
||||
// Doxygen commands.
|
||||
def Fn : DeclarationVerbatimLineCommand<"fn">;
|
||||
def Namespace : DeclarationVerbatimLineCommand<"namespace">;
|
||||
def Overload : DeclarationVerbatimLineCommand<"overload">;
|
||||
def Property : DeclarationVerbatimLineCommand<"property">;
|
||||
def Typedef : DeclarationVerbatimLineCommand<"typedef">;
|
||||
def Var : DeclarationVerbatimLineCommand<"var">;
|
||||
|
||||
// HeaderDoc commands.
|
||||
def Class : DeclarationVerbatimLineCommand<"class">;
|
||||
def Interface : DeclarationVerbatimLineCommand<"interface">;
|
||||
def Protocol : DeclarationVerbatimLineCommand<"protocol">;
|
||||
def Category : DeclarationVerbatimLineCommand<"category">;
|
||||
def Template : DeclarationVerbatimLineCommand<"template">;
|
||||
def Function : DeclarationVerbatimLineCommand<"function">;
|
||||
def Method : DeclarationVerbatimLineCommand<"method">;
|
||||
def Callback : DeclarationVerbatimLineCommand<"callback">;
|
||||
def Const : DeclarationVerbatimLineCommand<"const">;
|
||||
def Constant : DeclarationVerbatimLineCommand<"constant">;
|
||||
def Struct : DeclarationVerbatimLineCommand<"struct">;
|
||||
def Union : DeclarationVerbatimLineCommand<"union">;
|
||||
def Enum : DeclarationVerbatimLineCommand<"enum">;
|
||||
|
54
include/clang/AST/CommentHTMLTags.td
Normal file
54
include/clang/AST/CommentHTMLTags.td
Normal file
@ -0,0 +1,54 @@
|
||||
class Tag<string spelling> {
|
||||
string Spelling = spelling;
|
||||
bit EndTagOptional = 0;
|
||||
bit EndTagForbidden = 0;
|
||||
}
|
||||
|
||||
def Em : Tag<"em">;
|
||||
def Strong : Tag<"strong">;
|
||||
def Tt : Tag<"tt">;
|
||||
def I : Tag<"i">;
|
||||
def B : Tag<"b">;
|
||||
def Big : Tag<"big">;
|
||||
def Small : Tag<"small">;
|
||||
def Strike : Tag<"strike">;
|
||||
def S : Tag<"s">;
|
||||
def U : Tag<"u">;
|
||||
def Font : Tag<"font">;
|
||||
def A : Tag<"a">;
|
||||
def Hr : Tag<"hr"> { let EndTagForbidden = 1; }
|
||||
def Div : Tag<"div">;
|
||||
def Span : Tag<"span">;
|
||||
def H1 : Tag<"h1">;
|
||||
def H2 : Tag<"h2">;
|
||||
def H3 : Tag<"h3">;
|
||||
def H4 : Tag<"h4">;
|
||||
def H5 : Tag<"h5">;
|
||||
def H6 : Tag<"h6">;
|
||||
def Code : Tag<"code">;
|
||||
def Blockquote : Tag<"blockquote">;
|
||||
def Sub : Tag<"sub">;
|
||||
def Sup : Tag<"sup">;
|
||||
def Img : Tag<"img"> { let EndTagForbidden = 1; }
|
||||
def P : Tag<"p"> { let EndTagOptional = 1; }
|
||||
def Br : Tag<"br"> { let EndTagForbidden = 1; }
|
||||
def Pre : Tag<"pre">;
|
||||
def Ins : Tag<"ins">;
|
||||
def Del : Tag<"del">;
|
||||
def Ul : Tag<"ul">;
|
||||
def Ol : Tag<"ol">;
|
||||
def Li : Tag<"li"> { let EndTagOptional = 1; }
|
||||
def Dl : Tag<"dl">;
|
||||
def Dt : Tag<"dt"> { let EndTagOptional = 1; }
|
||||
def Dd : Tag<"dd"> { let EndTagOptional = 1; }
|
||||
def Table : Tag<"table">;
|
||||
def Caption : Tag<"caption">;
|
||||
def Thead : Tag<"thead"> { let EndTagOptional = 1; }
|
||||
def Tfoot : Tag<"tfoot"> { let EndTagOptional = 1; }
|
||||
def Tbody : Tag<"tbody"> { let EndTagOptional = 1; }
|
||||
def Colgroup : Tag<"colgroup"> { let EndTagOptional = 1; }
|
||||
def Col : Tag<"col"> { let EndTagForbidden = 1; }
|
||||
def Tr : Tag<"tr"> { let EndTagOptional = 1; }
|
||||
def Th : Tag<"th"> { let EndTagOptional = 1; }
|
||||
def Td : Tag<"td"> { let EndTagOptional = 1; }
|
||||
|
@ -26,6 +26,7 @@ namespace comments {
|
||||
|
||||
class Lexer;
|
||||
class TextTokenRetokenizer;
|
||||
struct CommandInfo;
|
||||
class CommandTraits;
|
||||
|
||||
namespace tok {
|
||||
@ -33,7 +34,8 @@ enum TokenKind {
|
||||
eof,
|
||||
newline,
|
||||
text,
|
||||
command,
|
||||
unknown_command, // Command that does not have an ID.
|
||||
command, // Command with an ID.
|
||||
verbatim_block_begin,
|
||||
verbatim_block_line,
|
||||
verbatim_block_end,
|
||||
@ -49,11 +51,6 @@ enum TokenKind {
|
||||
};
|
||||
} // end namespace tok
|
||||
|
||||
class CommentOptions {
|
||||
public:
|
||||
bool Markdown;
|
||||
};
|
||||
|
||||
/// \brief Comment token.
|
||||
class Token {
|
||||
friend class Lexer;
|
||||
@ -70,8 +67,14 @@ class Token {
|
||||
unsigned Length;
|
||||
|
||||
/// Contains text value associated with a token.
|
||||
const char *TextPtr1;
|
||||
unsigned TextLen1;
|
||||
const char *TextPtr;
|
||||
|
||||
/// Integer value associated with a token.
|
||||
///
|
||||
/// If the token is a konwn command, contains command ID and TextPtr is
|
||||
/// unused (command spelling can be found with CommandTraits). Otherwise,
|
||||
/// contains the length of the string that starts at TextPtr.
|
||||
unsigned IntVal;
|
||||
|
||||
public:
|
||||
SourceLocation getLocation() const LLVM_READONLY { return Loc; }
|
||||
@ -94,113 +97,120 @@ class Token {
|
||||
|
||||
StringRef getText() const LLVM_READONLY {
|
||||
assert(is(tok::text));
|
||||
return StringRef(TextPtr1, TextLen1);
|
||||
return StringRef(TextPtr, IntVal);
|
||||
}
|
||||
|
||||
void setText(StringRef Text) {
|
||||
assert(is(tok::text));
|
||||
TextPtr1 = Text.data();
|
||||
TextLen1 = Text.size();
|
||||
TextPtr = Text.data();
|
||||
IntVal = Text.size();
|
||||
}
|
||||
|
||||
StringRef getCommandName() const LLVM_READONLY {
|
||||
StringRef getUnknownCommandName() const LLVM_READONLY {
|
||||
assert(is(tok::unknown_command));
|
||||
return StringRef(TextPtr, IntVal);
|
||||
}
|
||||
|
||||
void setUnknownCommandName(StringRef Name) {
|
||||
assert(is(tok::unknown_command));
|
||||
TextPtr = Name.data();
|
||||
IntVal = Name.size();
|
||||
}
|
||||
|
||||
unsigned getCommandID() const LLVM_READONLY {
|
||||
assert(is(tok::command));
|
||||
return StringRef(TextPtr1, TextLen1);
|
||||
return IntVal;
|
||||
}
|
||||
|
||||
void setCommandName(StringRef Name) {
|
||||
void setCommandID(unsigned ID) {
|
||||
assert(is(tok::command));
|
||||
TextPtr1 = Name.data();
|
||||
TextLen1 = Name.size();
|
||||
IntVal = ID;
|
||||
}
|
||||
|
||||
StringRef getVerbatimBlockName() const LLVM_READONLY {
|
||||
unsigned getVerbatimBlockID() const LLVM_READONLY {
|
||||
assert(is(tok::verbatim_block_begin) || is(tok::verbatim_block_end));
|
||||
return StringRef(TextPtr1, TextLen1);
|
||||
return IntVal;
|
||||
}
|
||||
|
||||
void setVerbatimBlockName(StringRef Name) {
|
||||
void setVerbatimBlockID(unsigned ID) {
|
||||
assert(is(tok::verbatim_block_begin) || is(tok::verbatim_block_end));
|
||||
TextPtr1 = Name.data();
|
||||
TextLen1 = Name.size();
|
||||
IntVal = ID;
|
||||
}
|
||||
|
||||
StringRef getVerbatimBlockText() const LLVM_READONLY {
|
||||
assert(is(tok::verbatim_block_line));
|
||||
return StringRef(TextPtr1, TextLen1);
|
||||
return StringRef(TextPtr, IntVal);
|
||||
}
|
||||
|
||||
void setVerbatimBlockText(StringRef Text) {
|
||||
assert(is(tok::verbatim_block_line));
|
||||
TextPtr1 = Text.data();
|
||||
TextLen1 = Text.size();
|
||||
TextPtr = Text.data();
|
||||
IntVal = Text.size();
|
||||
}
|
||||
|
||||
/// Returns the name of verbatim line command.
|
||||
StringRef getVerbatimLineName() const LLVM_READONLY {
|
||||
unsigned getVerbatimLineID() const LLVM_READONLY {
|
||||
assert(is(tok::verbatim_line_name));
|
||||
return StringRef(TextPtr1, TextLen1);
|
||||
return IntVal;
|
||||
}
|
||||
|
||||
void setVerbatimLineName(StringRef Name) {
|
||||
void setVerbatimLineID(unsigned ID) {
|
||||
assert(is(tok::verbatim_line_name));
|
||||
TextPtr1 = Name.data();
|
||||
TextLen1 = Name.size();
|
||||
IntVal = ID;
|
||||
}
|
||||
|
||||
StringRef getVerbatimLineText() const LLVM_READONLY {
|
||||
assert(is(tok::verbatim_line_text));
|
||||
return StringRef(TextPtr1, TextLen1);
|
||||
return StringRef(TextPtr, IntVal);
|
||||
}
|
||||
|
||||
void setVerbatimLineText(StringRef Text) {
|
||||
assert(is(tok::verbatim_line_text));
|
||||
TextPtr1 = Text.data();
|
||||
TextLen1 = Text.size();
|
||||
TextPtr = Text.data();
|
||||
IntVal = Text.size();
|
||||
}
|
||||
|
||||
StringRef getHTMLTagStartName() const LLVM_READONLY {
|
||||
assert(is(tok::html_start_tag));
|
||||
return StringRef(TextPtr1, TextLen1);
|
||||
return StringRef(TextPtr, IntVal);
|
||||
}
|
||||
|
||||
void setHTMLTagStartName(StringRef Name) {
|
||||
assert(is(tok::html_start_tag));
|
||||
TextPtr1 = Name.data();
|
||||
TextLen1 = Name.size();
|
||||
TextPtr = Name.data();
|
||||
IntVal = Name.size();
|
||||
}
|
||||
|
||||
StringRef getHTMLIdent() const LLVM_READONLY {
|
||||
assert(is(tok::html_ident));
|
||||
return StringRef(TextPtr1, TextLen1);
|
||||
return StringRef(TextPtr, IntVal);
|
||||
}
|
||||
|
||||
void setHTMLIdent(StringRef Name) {
|
||||
assert(is(tok::html_ident));
|
||||
TextPtr1 = Name.data();
|
||||
TextLen1 = Name.size();
|
||||
TextPtr = Name.data();
|
||||
IntVal = Name.size();
|
||||
}
|
||||
|
||||
StringRef getHTMLQuotedString() const LLVM_READONLY {
|
||||
assert(is(tok::html_quoted_string));
|
||||
return StringRef(TextPtr1, TextLen1);
|
||||
return StringRef(TextPtr, IntVal);
|
||||
}
|
||||
|
||||
void setHTMLQuotedString(StringRef Str) {
|
||||
assert(is(tok::html_quoted_string));
|
||||
TextPtr1 = Str.data();
|
||||
TextLen1 = Str.size();
|
||||
TextPtr = Str.data();
|
||||
IntVal = Str.size();
|
||||
}
|
||||
|
||||
StringRef getHTMLTagEndName() const LLVM_READONLY {
|
||||
assert(is(tok::html_end_tag));
|
||||
return StringRef(TextPtr1, TextLen1);
|
||||
return StringRef(TextPtr, IntVal);
|
||||
}
|
||||
|
||||
void setHTMLTagEndName(StringRef Name) {
|
||||
assert(is(tok::html_end_tag));
|
||||
TextPtr1 = Name.data();
|
||||
TextLen1 = Name.size();
|
||||
TextPtr = Name.data();
|
||||
IntVal = Name.size();
|
||||
}
|
||||
|
||||
void dump(const Lexer &L, const SourceManager &SM) const;
|
||||
@ -209,8 +219,8 @@ class Token {
|
||||
/// \brief Comment lexer.
|
||||
class Lexer {
|
||||
private:
|
||||
Lexer(const Lexer&); // DO NOT IMPLEMENT
|
||||
void operator=(const Lexer&); // DO NOT IMPLEMENT
|
||||
Lexer(const Lexer &) LLVM_DELETED_FUNCTION;
|
||||
void operator=(const Lexer &) LLVM_DELETED_FUNCTION;
|
||||
|
||||
/// Allocator for strings that are semantic values of tokens and have to be
|
||||
/// computed (for example, resolved decimal character references).
|
||||
@ -221,7 +231,6 @@ class Lexer {
|
||||
const char *const BufferStart;
|
||||
const char *const BufferEnd;
|
||||
SourceLocation FileLoc;
|
||||
CommentOptions CommOpts;
|
||||
|
||||
const char *BufferPtr;
|
||||
|
||||
@ -286,8 +295,8 @@ class Lexer {
|
||||
Result.setKind(Kind);
|
||||
Result.setLength(TokLen);
|
||||
#ifndef NDEBUG
|
||||
Result.TextPtr1 = "<UNSET>";
|
||||
Result.TextLen1 = 7;
|
||||
Result.TextPtr = "<UNSET>";
|
||||
Result.IntVal = 7;
|
||||
#endif
|
||||
BufferPtr = TokEnd;
|
||||
}
|
||||
@ -314,13 +323,14 @@ class Lexer {
|
||||
|
||||
void setupAndLexVerbatimBlock(Token &T,
|
||||
const char *TextBegin,
|
||||
char Marker, StringRef EndName);
|
||||
char Marker, const CommandInfo *Info);
|
||||
|
||||
void lexVerbatimBlockFirstLine(Token &T);
|
||||
|
||||
void lexVerbatimBlockBody(Token &T);
|
||||
|
||||
void setupAndLexVerbatimLine(Token &T, const char *TextBegin);
|
||||
void setupAndLexVerbatimLine(Token &T, const char *TextBegin,
|
||||
const CommandInfo *Info);
|
||||
|
||||
void lexVerbatimLineText(Token &T);
|
||||
|
||||
@ -336,7 +346,7 @@ class Lexer {
|
||||
|
||||
public:
|
||||
Lexer(llvm::BumpPtrAllocator &Allocator, const CommandTraits &Traits,
|
||||
SourceLocation FileLoc, const CommentOptions &CommOpts,
|
||||
SourceLocation FileLoc,
|
||||
const char *BufferStart, const char *BufferEnd);
|
||||
|
||||
void lex(Token &T);
|
||||
|
@ -28,8 +28,8 @@ class CommandTraits;
|
||||
|
||||
/// Doxygen comment parser.
|
||||
class Parser {
|
||||
Parser(const Parser&); // DO NOT IMPLEMENT
|
||||
void operator=(const Parser&); // DO NOT IMPLEMENT
|
||||
Parser(const Parser &) LLVM_DELETED_FUNCTION;
|
||||
void operator=(const Parser &) LLVM_DELETED_FUNCTION;
|
||||
|
||||
friend class TextTokenRetokenizer;
|
||||
|
||||
|
@ -25,13 +25,14 @@
|
||||
namespace clang {
|
||||
class Decl;
|
||||
class SourceMgr;
|
||||
class Preprocessor;
|
||||
|
||||
namespace comments {
|
||||
class CommandTraits;
|
||||
|
||||
class Sema {
|
||||
Sema(const Sema&); // DO NOT IMPLEMENT
|
||||
void operator=(const Sema&); // DO NOT IMPLEMENT
|
||||
Sema(const Sema &) LLVM_DELETED_FUNCTION;
|
||||
void operator=(const Sema &) LLVM_DELETED_FUNCTION;
|
||||
|
||||
/// Allocator for AST nodes.
|
||||
llvm::BumpPtrAllocator &Allocator;
|
||||
@ -41,18 +42,13 @@ class Sema {
|
||||
|
||||
DiagnosticsEngine &Diags;
|
||||
|
||||
const CommandTraits &Traits;
|
||||
CommandTraits &Traits;
|
||||
|
||||
const Preprocessor *PP;
|
||||
|
||||
/// Information about the declaration this comment is attached to.
|
||||
DeclInfo *ThisDeclInfo;
|
||||
|
||||
/// Comment AST nodes that correspond to \c ParamVars for which we have
|
||||
/// found a \\param command or NULL if no documentation was found so far.
|
||||
///
|
||||
/// Has correct size and contains valid values if \c DeclInfo->IsFilled is
|
||||
/// true.
|
||||
llvm::SmallVector<ParamCommandComment *, 8> ParamVarDocs;
|
||||
|
||||
/// Comment AST nodes that correspond to parameter names in
|
||||
/// \c TemplateParameters.
|
||||
///
|
||||
@ -75,7 +71,8 @@ class Sema {
|
||||
|
||||
public:
|
||||
Sema(llvm::BumpPtrAllocator &Allocator, const SourceManager &SourceMgr,
|
||||
DiagnosticsEngine &Diags, const CommandTraits &Traits);
|
||||
DiagnosticsEngine &Diags, CommandTraits &Traits,
|
||||
const Preprocessor *PP);
|
||||
|
||||
void setDecl(const Decl *D);
|
||||
|
||||
@ -96,7 +93,7 @@ class Sema {
|
||||
|
||||
BlockCommandComment *actOnBlockCommandStart(SourceLocation LocBegin,
|
||||
SourceLocation LocEnd,
|
||||
StringRef Name);
|
||||
unsigned CommandID);
|
||||
|
||||
void actOnBlockCommandArgs(BlockCommandComment *Command,
|
||||
ArrayRef<BlockCommandComment::Argument> Args);
|
||||
@ -106,7 +103,7 @@ class Sema {
|
||||
|
||||
ParamCommandComment *actOnParamCommandStart(SourceLocation LocBegin,
|
||||
SourceLocation LocEnd,
|
||||
StringRef Name);
|
||||
unsigned CommandID);
|
||||
|
||||
void actOnParamCommandDirectionArg(ParamCommandComment *Command,
|
||||
SourceLocation ArgLocBegin,
|
||||
@ -123,7 +120,7 @@ class Sema {
|
||||
|
||||
TParamCommandComment *actOnTParamCommandStart(SourceLocation LocBegin,
|
||||
SourceLocation LocEnd,
|
||||
StringRef Name);
|
||||
unsigned CommandID);
|
||||
|
||||
void actOnTParamCommandParamNameArg(TParamCommandComment *Command,
|
||||
SourceLocation ArgLocBegin,
|
||||
@ -135,25 +132,29 @@ class Sema {
|
||||
|
||||
InlineCommandComment *actOnInlineCommand(SourceLocation CommandLocBegin,
|
||||
SourceLocation CommandLocEnd,
|
||||
StringRef CommandName);
|
||||
unsigned CommandID);
|
||||
|
||||
InlineCommandComment *actOnInlineCommand(SourceLocation CommandLocBegin,
|
||||
SourceLocation CommandLocEnd,
|
||||
StringRef CommandName,
|
||||
unsigned CommandID,
|
||||
SourceLocation ArgLocBegin,
|
||||
SourceLocation ArgLocEnd,
|
||||
StringRef Arg);
|
||||
|
||||
InlineContentComment *actOnUnknownCommand(SourceLocation LocBegin,
|
||||
SourceLocation LocEnd,
|
||||
StringRef Name);
|
||||
StringRef CommandName);
|
||||
|
||||
InlineContentComment *actOnUnknownCommand(SourceLocation LocBegin,
|
||||
SourceLocation LocEnd,
|
||||
unsigned CommandID);
|
||||
|
||||
TextComment *actOnText(SourceLocation LocBegin,
|
||||
SourceLocation LocEnd,
|
||||
StringRef Text);
|
||||
|
||||
VerbatimBlockComment *actOnVerbatimBlockStart(SourceLocation Loc,
|
||||
StringRef Name);
|
||||
unsigned CommandID);
|
||||
|
||||
VerbatimBlockLineComment *actOnVerbatimBlockLine(SourceLocation Loc,
|
||||
StringRef Text);
|
||||
@ -164,7 +165,7 @@ class Sema {
|
||||
ArrayRef<VerbatimBlockLineComment *> Lines);
|
||||
|
||||
VerbatimLineComment *actOnVerbatimLine(SourceLocation LocBegin,
|
||||
StringRef Name,
|
||||
unsigned CommandID,
|
||||
SourceLocation TextBegin,
|
||||
StringRef Text);
|
||||
|
||||
@ -190,6 +191,12 @@ class Sema {
|
||||
/// used only once per comment, e.g., \\brief and \\returns.
|
||||
void checkBlockCommandDuplicate(const BlockCommandComment *Command);
|
||||
|
||||
void checkDeprecatedCommand(const BlockCommandComment *Comment);
|
||||
|
||||
/// Resolve parameter names to parameter indexes in function declaration.
|
||||
/// Emit diagnostics about unknown parametrs.
|
||||
void resolveParamCommandIndexes(const FullComment *FC);
|
||||
|
||||
bool isFunctionDecl();
|
||||
bool isTemplateOrSpecialization();
|
||||
|
||||
@ -218,9 +225,6 @@ class Sema {
|
||||
|
||||
InlineCommandComment::RenderKind
|
||||
getInlineCommandRenderKind(StringRef Name) const;
|
||||
|
||||
bool isHTMLEndTagOptional(StringRef Name);
|
||||
bool isHTMLEndTagForbidden(StringRef Name);
|
||||
};
|
||||
|
||||
} // end namespace comments
|
||||
|
@ -88,7 +88,6 @@ class TranslationUnitDecl : public Decl, public DeclContext {
|
||||
static TranslationUnitDecl *Create(ASTContext &C);
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const TranslationUnitDecl *D) { return true; }
|
||||
static bool classofKind(Kind K) { return K == TranslationUnit; }
|
||||
static DeclContext *castToDeclContext(const TranslationUnitDecl *D) {
|
||||
return static_cast<DeclContext *>(const_cast<TranslationUnitDecl*>(D));
|
||||
@ -214,16 +213,19 @@ class NamedDecl : public Decl {
|
||||
bool isCXXInstanceMember() const;
|
||||
|
||||
class LinkageInfo {
|
||||
Linkage linkage_;
|
||||
Visibility visibility_;
|
||||
bool explicit_;
|
||||
uint8_t linkage_ : 2;
|
||||
uint8_t visibility_ : 2;
|
||||
uint8_t explicit_ : 1;
|
||||
|
||||
void setVisibility(Visibility V, bool E) { visibility_ = V; explicit_ = E; }
|
||||
public:
|
||||
LinkageInfo() : linkage_(ExternalLinkage), visibility_(DefaultVisibility),
|
||||
explicit_(false) {}
|
||||
LinkageInfo(Linkage L, Visibility V, bool E)
|
||||
: linkage_(L), visibility_(V), explicit_(E) {}
|
||||
: linkage_(L), visibility_(V), explicit_(E) {
|
||||
assert(linkage() == L && visibility() == V && visibilityExplicit() == E &&
|
||||
"Enum truncated!");
|
||||
}
|
||||
|
||||
static LinkageInfo external() {
|
||||
return LinkageInfo();
|
||||
@ -238,8 +240,8 @@ class NamedDecl : public Decl {
|
||||
return LinkageInfo(NoLinkage, DefaultVisibility, false);
|
||||
}
|
||||
|
||||
Linkage linkage() const { return linkage_; }
|
||||
Visibility visibility() const { return visibility_; }
|
||||
Linkage linkage() const { return (Linkage)linkage_; }
|
||||
Visibility visibility() const { return (Visibility)visibility_; }
|
||||
bool visibilityExplicit() const { return explicit_; }
|
||||
|
||||
void setLinkage(Linkage L) { linkage_ = L; }
|
||||
@ -337,7 +339,6 @@ class NamedDecl : public Decl {
|
||||
}
|
||||
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const NamedDecl *D) { return true; }
|
||||
static bool classofKind(Kind K) { return K >= firstNamed && K <= lastNamed; }
|
||||
};
|
||||
|
||||
@ -383,7 +384,6 @@ class LabelDecl : public NamedDecl {
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const LabelDecl *D) { return true; }
|
||||
static bool classofKind(Kind K) { return K == Label; }
|
||||
};
|
||||
|
||||
@ -509,7 +509,6 @@ class NamespaceDecl : public NamedDecl, public DeclContext,
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const NamespaceDecl *D) { return true; }
|
||||
static bool classofKind(Kind K) { return K == Namespace; }
|
||||
static DeclContext *castToDeclContext(const NamespaceDecl *D) {
|
||||
return static_cast<DeclContext *>(const_cast<NamespaceDecl*>(D));
|
||||
@ -545,7 +544,6 @@ class ValueDecl : public NamedDecl {
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const ValueDecl *D) { return true; }
|
||||
static bool classofKind(Kind K) { return K >= firstValue && K <= lastValue; }
|
||||
};
|
||||
|
||||
@ -578,8 +576,8 @@ struct QualifierInfo {
|
||||
|
||||
private:
|
||||
// Copy constructor and copy assignment are disabled.
|
||||
QualifierInfo(const QualifierInfo&);
|
||||
QualifierInfo& operator=(const QualifierInfo&);
|
||||
QualifierInfo(const QualifierInfo&) LLVM_DELETED_FUNCTION;
|
||||
QualifierInfo& operator=(const QualifierInfo&) LLVM_DELETED_FUNCTION;
|
||||
};
|
||||
|
||||
/// \brief Represents a ValueDecl that came out of a declarator.
|
||||
@ -666,7 +664,6 @@ class DeclaratorDecl : public ValueDecl {
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const DeclaratorDecl *D) { return true; }
|
||||
static bool classofKind(Kind K) {
|
||||
return K >= firstDeclarator && K <= lastDeclarator;
|
||||
}
|
||||
@ -712,7 +709,7 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
|
||||
typedef clang::StorageClass StorageClass;
|
||||
|
||||
/// getStorageClassSpecifierString - Return the string used to
|
||||
/// specify the storage class \arg SC.
|
||||
/// specify the storage class \p SC.
|
||||
///
|
||||
/// It is illegal to call this function with SC == None.
|
||||
static const char *getStorageClassSpecifierString(StorageClass SC);
|
||||
@ -1208,7 +1205,6 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const VarDecl *D) { return true; }
|
||||
static bool classofKind(Kind K) { return K >= firstVar && K <= lastVar; }
|
||||
};
|
||||
|
||||
@ -1229,7 +1225,6 @@ class ImplicitParamDecl : public VarDecl {
|
||||
}
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const ImplicitParamDecl *D) { return true; }
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classofKind(Kind K) { return K == ImplicitParam; }
|
||||
};
|
||||
@ -1399,7 +1394,6 @@ class ParmVarDecl : public VarDecl {
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const ParmVarDecl *D) { return true; }
|
||||
static bool classofKind(Kind K) { return K == ParmVar; }
|
||||
|
||||
private:
|
||||
@ -2070,7 +2064,6 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext,
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const FunctionDecl *D) { return true; }
|
||||
static bool classofKind(Kind K) {
|
||||
return K >= firstFunction && K <= lastFunction;
|
||||
}
|
||||
@ -2204,7 +2197,6 @@ class FieldDecl : public DeclaratorDecl {
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const FieldDecl *D) { return true; }
|
||||
static bool classofKind(Kind K) { return K >= firstField && K <= lastField; }
|
||||
|
||||
friend class ASTDeclReader;
|
||||
@ -2243,7 +2235,6 @@ class EnumConstantDecl : public ValueDecl {
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const EnumConstantDecl *D) { return true; }
|
||||
static bool classofKind(Kind K) { return K == EnumConstant; }
|
||||
|
||||
friend class StmtIteratorBase;
|
||||
@ -2287,7 +2278,6 @@ class IndirectFieldDecl : public ValueDecl {
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const IndirectFieldDecl *D) { return true; }
|
||||
static bool classofKind(Kind K) { return K == IndirectField; }
|
||||
friend class ASTDeclReader;
|
||||
};
|
||||
@ -2334,7 +2324,6 @@ class TypeDecl : public NamedDecl {
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const TypeDecl *D) { return true; }
|
||||
static bool classofKind(Kind K) { return K >= firstType && K <= lastType; }
|
||||
};
|
||||
|
||||
@ -2390,7 +2379,6 @@ class TypedefNameDecl : public TypeDecl, public Redeclarable<TypedefNameDecl> {
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const TypedefNameDecl *D) { return true; }
|
||||
static bool classofKind(Kind K) {
|
||||
return K >= firstTypedefName && K <= lastTypedefName;
|
||||
}
|
||||
@ -2413,7 +2401,6 @@ class TypedefDecl : public TypedefNameDecl {
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const TypedefDecl *D) { return true; }
|
||||
static bool classofKind(Kind K) { return K == Typedef; }
|
||||
};
|
||||
|
||||
@ -2434,7 +2421,6 @@ class TypeAliasDecl : public TypedefNameDecl {
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const TypeAliasDecl *D) { return true; }
|
||||
static bool classofKind(Kind K) { return K == TypeAlias; }
|
||||
};
|
||||
|
||||
@ -2448,7 +2434,7 @@ class TagDecl
|
||||
private:
|
||||
// FIXME: This can be packed into the bitfields in Decl.
|
||||
/// TagDeclKind - The TagKind enum.
|
||||
unsigned TagDeclKind : 2;
|
||||
unsigned TagDeclKind : 3;
|
||||
|
||||
/// IsCompleteDefinition - True if this is a definition ("struct foo
|
||||
/// {};"), false if it is a declaration ("struct foo;"). It is not
|
||||
@ -2625,6 +2611,7 @@ class TagDecl
|
||||
void setTagKind(TagKind TK) { TagDeclKind = TK; }
|
||||
|
||||
bool isStruct() const { return getTagKind() == TTK_Struct; }
|
||||
bool isInterface() const { return getTagKind() == TTK_Interface; }
|
||||
bool isClass() const { return getTagKind() == TTK_Class; }
|
||||
bool isUnion() const { return getTagKind() == TTK_Union; }
|
||||
bool isEnum() const { return getTagKind() == TTK_Enum; }
|
||||
@ -2665,7 +2652,6 @@ class TagDecl
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const TagDecl *D) { return true; }
|
||||
static bool classofKind(Kind K) { return K >= firstTag && K <= lastTag; }
|
||||
|
||||
static DeclContext *castToDeclContext(const TagDecl *D) {
|
||||
@ -2895,7 +2881,6 @@ class EnumDecl : public TagDecl {
|
||||
}
|
||||
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const EnumDecl *D) { return true; }
|
||||
static bool classofKind(Kind K) { return K == Enum; }
|
||||
|
||||
friend class ASTDeclReader;
|
||||
@ -3026,11 +3011,15 @@ class RecordDecl : public TagDecl {
|
||||
virtual void completeDefinition();
|
||||
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const RecordDecl *D) { return true; }
|
||||
static bool classofKind(Kind K) {
|
||||
return K >= firstRecord && K <= lastRecord;
|
||||
}
|
||||
|
||||
/// isMsStrust - Get whether or not this is an ms_struct which can
|
||||
/// be turned on with an attribute, pragma, or -mms-bitfields
|
||||
/// commandline option.
|
||||
bool isMsStruct(const ASTContext &C) const;
|
||||
|
||||
private:
|
||||
/// \brief Deserialize just the fields.
|
||||
void LoadFieldsFromExternalStorage() const;
|
||||
@ -3062,7 +3051,6 @@ class FileScopeAsmDecl : public Decl {
|
||||
void setAsmString(StringLiteral *Asm) { AsmString = Asm; }
|
||||
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const FileScopeAsmDecl *D) { return true; }
|
||||
static bool classofKind(Kind K) { return K == FileScopeAsm; }
|
||||
};
|
||||
|
||||
@ -3208,7 +3196,6 @@ class BlockDecl : public Decl, public DeclContext {
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const BlockDecl *D) { return true; }
|
||||
static bool classofKind(Kind K) { return K == Block; }
|
||||
static DeclContext *castToDeclContext(const BlockDecl *D) {
|
||||
return static_cast<DeclContext *>(const_cast<BlockDecl*>(D));
|
||||
@ -3282,7 +3269,6 @@ class ImportDecl : public Decl {
|
||||
virtual SourceRange getSourceRange() const LLVM_READONLY;
|
||||
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const ImportDecl *D) { return true; }
|
||||
static bool classofKind(Kind K) { return K == Import; }
|
||||
};
|
||||
|
||||
|
@ -430,16 +430,10 @@ class Decl {
|
||||
void dropAttr() {
|
||||
if (!HasAttrs) return;
|
||||
|
||||
AttrVec &Attrs = getAttrs();
|
||||
for (unsigned i = 0, e = Attrs.size(); i != e; /* in loop */) {
|
||||
if (isa<T>(Attrs[i])) {
|
||||
Attrs.erase(Attrs.begin() + i);
|
||||
--e;
|
||||
}
|
||||
else
|
||||
++i;
|
||||
}
|
||||
if (Attrs.empty())
|
||||
AttrVec &Vec = getAttrs();
|
||||
Vec.erase(std::remove_if(Vec.begin(), Vec.end(), isa<T, Attr*>), Vec.end());
|
||||
|
||||
if (Vec.empty())
|
||||
HasAttrs = false;
|
||||
}
|
||||
|
||||
@ -844,8 +838,6 @@ class Decl {
|
||||
IdentifierNamespace |= IDNS_NonMemberOperator;
|
||||
}
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *) { return true; }
|
||||
static bool classofKind(Kind K) { return true; }
|
||||
static DeclContext *castToDeclContext(const Decl *);
|
||||
static Decl *castFromDeclContext(const DeclContext *);
|
||||
@ -1479,6 +1471,13 @@ class DeclContext {
|
||||
inline ddiag_iterator ddiag_end() const;
|
||||
|
||||
// Low-level accessors
|
||||
|
||||
/// \brief Mark the lookup table as needing to be built. This should be
|
||||
/// used only if setHasExternalLexicalStorage() has been called.
|
||||
void setMustBuildLookupTable() {
|
||||
assert(ExternalLexicalStorage && "Requires external lexical storage");
|
||||
LookupPtr.setInt(true);
|
||||
}
|
||||
|
||||
/// \brief Retrieve the internal representation of the lookup structure.
|
||||
/// This may omit some names if we are lazily building the structure.
|
||||
@ -1516,10 +1515,6 @@ class DeclContext {
|
||||
|
||||
static bool classof(const Decl *D);
|
||||
static bool classof(const DeclContext *D) { return true; }
|
||||
#define DECL(NAME, BASE)
|
||||
#define DECL_CONTEXT(NAME) \
|
||||
static bool classof(const NAME##Decl *D) { return true; }
|
||||
#include "clang/AST/DeclNodes.inc"
|
||||
|
||||
LLVM_ATTRIBUTE_USED void dumpDeclContext() const;
|
||||
|
||||
|
@ -145,7 +145,6 @@ class AccessSpecDecl : public Decl {
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const AccessSpecDecl *D) { return true; }
|
||||
static bool classofKind(Kind K) { return K == AccessSpec; }
|
||||
};
|
||||
|
||||
@ -563,9 +562,10 @@ class CXXRecordDecl : public RecordDecl {
|
||||
struct LambdaDefinitionData : public DefinitionData {
|
||||
typedef LambdaExpr::Capture Capture;
|
||||
|
||||
LambdaDefinitionData(CXXRecordDecl *D, bool Dependent)
|
||||
LambdaDefinitionData(CXXRecordDecl *D, TypeSourceInfo *Info, bool Dependent)
|
||||
: DefinitionData(D), Dependent(Dependent), NumCaptures(0),
|
||||
NumExplicitCaptures(0), ManglingNumber(0), ContextDecl(0), Captures(0)
|
||||
NumExplicitCaptures(0), ManglingNumber(0), ContextDecl(0), Captures(0),
|
||||
MethodTyInfo(Info)
|
||||
{
|
||||
IsLambda = true;
|
||||
}
|
||||
@ -598,7 +598,10 @@ class CXXRecordDecl : public RecordDecl {
|
||||
|
||||
/// \brief The list of captures, both explicit and implicit, for this
|
||||
/// lambda.
|
||||
Capture *Captures;
|
||||
Capture *Captures;
|
||||
|
||||
/// \brief The type of the call method.
|
||||
TypeSourceInfo *MethodTyInfo;
|
||||
};
|
||||
|
||||
struct DefinitionData &data() {
|
||||
@ -705,7 +708,8 @@ class CXXRecordDecl : public RecordDecl {
|
||||
IdentifierInfo *Id, CXXRecordDecl* PrevDecl=0,
|
||||
bool DelayTypeCreation = false);
|
||||
static CXXRecordDecl *CreateLambda(const ASTContext &C, DeclContext *DC,
|
||||
SourceLocation Loc, bool DependentLambda);
|
||||
TypeSourceInfo *Info, SourceLocation Loc,
|
||||
bool DependentLambda);
|
||||
static CXXRecordDecl *CreateDeserialized(const ASTContext &C, unsigned ID);
|
||||
|
||||
bool isDynamicClass() const {
|
||||
@ -1303,7 +1307,7 @@ class CXXRecordDecl : public RecordDecl {
|
||||
|
||||
/// \brief Function type used by forallBases() as a callback.
|
||||
///
|
||||
/// \param Base the definition of the base class
|
||||
/// \param BaseDefinition the definition of the base class
|
||||
///
|
||||
/// \returns true if this base matched the search criteria
|
||||
typedef bool ForallBasesCallback(const CXXRecordDecl *BaseDefinition,
|
||||
@ -1500,15 +1504,15 @@ class CXXRecordDecl : public RecordDecl {
|
||||
bool isDependentLambda() const {
|
||||
return isLambda() && getLambdaData().Dependent;
|
||||
}
|
||||
|
||||
|
||||
TypeSourceInfo *getLambdaTypeInfo() const {
|
||||
return getLambdaData().MethodTyInfo;
|
||||
}
|
||||
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classofKind(Kind K) {
|
||||
return K >= firstCXXRecord && K <= lastCXXRecord;
|
||||
}
|
||||
static bool classof(const CXXRecordDecl *D) { return true; }
|
||||
static bool classof(const ClassTemplateSpecializationDecl *D) {
|
||||
return true;
|
||||
}
|
||||
|
||||
friend class ASTDeclReader;
|
||||
friend class ASTDeclWriter;
|
||||
@ -1549,14 +1553,16 @@ class CXXMethodDecl : public FunctionDecl {
|
||||
bool isStatic() const { return getStorageClass() == SC_Static; }
|
||||
bool isInstance() const { return !isStatic(); }
|
||||
|
||||
bool isConst() { return getType()->castAs<FunctionType>()->isConst(); }
|
||||
bool isVolatile() { return getType()->castAs<FunctionType>()->isVolatile(); }
|
||||
bool isConst() const { return getType()->castAs<FunctionType>()->isConst(); }
|
||||
bool isVolatile() const { return getType()->castAs<FunctionType>()->isVolatile(); }
|
||||
|
||||
bool isVirtual() const {
|
||||
CXXMethodDecl *CD =
|
||||
cast<CXXMethodDecl>(const_cast<CXXMethodDecl*>(this)->getCanonicalDecl());
|
||||
|
||||
if (CD->isVirtualAsWritten())
|
||||
// Methods declared in interfaces are automatically (pure) virtual.
|
||||
if (CD->isVirtualAsWritten() ||
|
||||
(CD->getParent()->isInterface() && CD->isUserProvided()))
|
||||
return true;
|
||||
|
||||
return (CD->begin_overridden_methods() != CD->end_overridden_methods());
|
||||
@ -1661,7 +1667,6 @@ class CXXMethodDecl : public FunctionDecl {
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const CXXMethodDecl *D) { return true; }
|
||||
static bool classofKind(Kind K) {
|
||||
return K >= firstCXXMethod && K <= lastCXXMethod;
|
||||
}
|
||||
@ -2141,7 +2146,6 @@ class CXXConstructorDecl : public CXXMethodDecl {
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const CXXConstructorDecl *D) { return true; }
|
||||
static bool classofKind(Kind K) { return K == CXXConstructor; }
|
||||
|
||||
friend class ASTDeclReader;
|
||||
@ -2213,7 +2217,6 @@ class CXXDestructorDecl : public CXXMethodDecl {
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const CXXDestructorDecl *D) { return true; }
|
||||
static bool classofKind(Kind K) { return K == CXXDestructor; }
|
||||
|
||||
friend class ASTDeclReader;
|
||||
@ -2280,7 +2283,6 @@ class CXXConversionDecl : public CXXMethodDecl {
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const CXXConversionDecl *D) { return true; }
|
||||
static bool classofKind(Kind K) { return K == CXXConversion; }
|
||||
|
||||
friend class ASTDeclReader;
|
||||
@ -2350,7 +2352,6 @@ class LinkageSpecDecl : public Decl, public DeclContext {
|
||||
}
|
||||
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const LinkageSpecDecl *D) { return true; }
|
||||
static bool classofKind(Kind K) { return K == LinkageSpec; }
|
||||
static DeclContext *castToDeclContext(const LinkageSpecDecl *D) {
|
||||
return static_cast<DeclContext *>(const_cast<LinkageSpecDecl*>(D));
|
||||
@ -2454,7 +2455,6 @@ class UsingDirectiveDecl : public NamedDecl {
|
||||
}
|
||||
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const UsingDirectiveDecl *D) { return true; }
|
||||
static bool classofKind(Kind K) { return K == UsingDirective; }
|
||||
|
||||
// Friend for getUsingDirectiveName.
|
||||
@ -2548,7 +2548,6 @@ class NamespaceAliasDecl : public NamedDecl {
|
||||
}
|
||||
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const NamespaceAliasDecl *D) { return true; }
|
||||
static bool classofKind(Kind K) { return K == NamespaceAlias; }
|
||||
};
|
||||
|
||||
@ -2619,7 +2618,6 @@ class UsingShadowDecl : public NamedDecl {
|
||||
}
|
||||
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const UsingShadowDecl *D) { return true; }
|
||||
static bool classofKind(Kind K) { return K == Decl::UsingShadow; }
|
||||
|
||||
friend class ASTDeclReader;
|
||||
@ -2751,7 +2749,6 @@ class UsingDecl : public NamedDecl {
|
||||
}
|
||||
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const UsingDecl *D) { return true; }
|
||||
static bool classofKind(Kind K) { return K == Using; }
|
||||
|
||||
friend class ASTDeclReader;
|
||||
@ -2825,7 +2822,6 @@ class UnresolvedUsingValueDecl : public ValueDecl {
|
||||
}
|
||||
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const UnresolvedUsingValueDecl *D) { return true; }
|
||||
static bool classofKind(Kind K) { return K == UnresolvedUsingValue; }
|
||||
|
||||
friend class ASTDeclReader;
|
||||
@ -2891,7 +2887,6 @@ class UnresolvedUsingTypenameDecl : public TypeDecl {
|
||||
CreateDeserialized(ASTContext &C, unsigned ID);
|
||||
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const UnresolvedUsingTypenameDecl *D) { return true; }
|
||||
static bool classofKind(Kind K) { return K == UnresolvedUsingTypename; }
|
||||
};
|
||||
|
||||
@ -2931,7 +2926,6 @@ class StaticAssertDecl : public Decl {
|
||||
}
|
||||
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(StaticAssertDecl *D) { return true; }
|
||||
static bool classofKind(Kind K) { return K == StaticAssert; }
|
||||
|
||||
friend class ASTDeclReader;
|
||||
|
@ -16,6 +16,7 @@
|
||||
#define LLVM_CLANG_AST_DECLFRIEND_H
|
||||
|
||||
#include "clang/AST/DeclCXX.h"
|
||||
#include "clang/AST/DeclTemplate.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
|
||||
namespace clang {
|
||||
@ -104,9 +105,15 @@ class FriendDecl : public Decl {
|
||||
|
||||
/// Retrieves the source range for the friend declaration.
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
/* FIXME: consider the case of templates wrt start of range. */
|
||||
if (NamedDecl *ND = getFriendDecl())
|
||||
if (NamedDecl *ND = getFriendDecl()) {
|
||||
if (FunctionTemplateDecl *FTD = dyn_cast<FunctionTemplateDecl>(ND))
|
||||
return FTD->getSourceRange();
|
||||
if (DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(ND)) {
|
||||
if (DD->getOuterLocStart() != DD->getInnerLocStart())
|
||||
return DD->getSourceRange();
|
||||
}
|
||||
return SourceRange(getFriendLoc(), ND->getLocEnd());
|
||||
}
|
||||
else if (TypeSourceInfo *TInfo = getFriendType())
|
||||
return SourceRange(getFriendLoc(), TInfo->getTypeLoc().getEndLoc());
|
||||
else
|
||||
@ -123,7 +130,6 @@ class FriendDecl : public Decl {
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const FriendDecl *D) { return true; }
|
||||
static bool classofKind(Kind K) { return K == Decl::Friend; }
|
||||
|
||||
friend class ASTDeclReader;
|
||||
|
@ -33,8 +33,8 @@ class ObjCPropertyImplDecl;
|
||||
class CXXCtorInitializer;
|
||||
|
||||
class ObjCListBase {
|
||||
void operator=(const ObjCListBase &); // DO NOT IMPLEMENT
|
||||
ObjCListBase(const ObjCListBase&); // DO NOT IMPLEMENT
|
||||
ObjCListBase(const ObjCListBase &) LLVM_DELETED_FUNCTION;
|
||||
void operator=(const ObjCListBase &) LLVM_DELETED_FUNCTION;
|
||||
protected:
|
||||
/// List is an array of pointers to objects that are not owned by this object.
|
||||
void **List;
|
||||
@ -123,8 +123,8 @@ class ObjCMethodDecl : public NamedDecl, public DeclContext {
|
||||
unsigned IsInstance : 1;
|
||||
unsigned IsVariadic : 1;
|
||||
|
||||
// Synthesized declaration method for a property setter/getter
|
||||
unsigned IsSynthesized : 1;
|
||||
/// True if this method is the getter or setter for an explicit property.
|
||||
unsigned IsPropertyAccessor : 1;
|
||||
|
||||
// Method has a definition.
|
||||
unsigned IsDefined : 1;
|
||||
@ -174,8 +174,7 @@ class ObjCMethodDecl : public NamedDecl, public DeclContext {
|
||||
SourceLocation DeclEndLoc; // the location of the ';' or '{'.
|
||||
|
||||
// The following are only used for method definitions, null otherwise.
|
||||
// FIXME: space savings opportunity, consider a sub-class.
|
||||
Stmt *Body;
|
||||
LazyDeclStmtPtr Body;
|
||||
|
||||
/// SelfDecl - Decl for the implicit self parameter. This is lazily
|
||||
/// constructed by createImplicitParams.
|
||||
@ -227,7 +226,7 @@ class ObjCMethodDecl : public NamedDecl, public DeclContext {
|
||||
DeclContext *contextDecl,
|
||||
bool isInstance = true,
|
||||
bool isVariadic = false,
|
||||
bool isSynthesized = false,
|
||||
bool isPropertyAccessor = false,
|
||||
bool isImplicitlyDeclared = false,
|
||||
bool isDefined = false,
|
||||
ImplementationControl impControl = None,
|
||||
@ -235,14 +234,14 @@ class ObjCMethodDecl : public NamedDecl, public DeclContext {
|
||||
: NamedDecl(ObjCMethod, contextDecl, beginLoc, SelInfo),
|
||||
DeclContext(ObjCMethod), Family(InvalidObjCMethodFamily),
|
||||
IsInstance(isInstance), IsVariadic(isVariadic),
|
||||
IsSynthesized(isSynthesized),
|
||||
IsPropertyAccessor(isPropertyAccessor),
|
||||
IsDefined(isDefined), IsRedeclaration(0), HasRedeclaration(0),
|
||||
DeclImplementation(impControl), objcDeclQualifier(OBJC_TQ_None),
|
||||
RelatedResultType(HasRelatedResultType),
|
||||
SelLocsKind(SelLoc_StandardNoSpace), IsOverriding(0),
|
||||
MethodDeclType(T), ResultTInfo(ResultTInfo),
|
||||
ParamsAndSelLocs(0), NumParams(0),
|
||||
DeclEndLoc(endLoc), Body(0), SelfDecl(0), CmdDecl(0) {
|
||||
DeclEndLoc(endLoc), Body(), SelfDecl(0), CmdDecl(0) {
|
||||
setImplicit(isImplicitlyDeclared);
|
||||
}
|
||||
|
||||
@ -261,7 +260,7 @@ class ObjCMethodDecl : public NamedDecl, public DeclContext {
|
||||
DeclContext *contextDecl,
|
||||
bool isInstance = true,
|
||||
bool isVariadic = false,
|
||||
bool isSynthesized = false,
|
||||
bool isPropertyAccessor = false,
|
||||
bool isImplicitlyDeclared = false,
|
||||
bool isDefined = false,
|
||||
ImplementationControl impControl = None,
|
||||
@ -363,7 +362,7 @@ class ObjCMethodDecl : public NamedDecl, public DeclContext {
|
||||
}
|
||||
|
||||
/// \brief Sets the method's parameters and selector source locations.
|
||||
/// If the method is implicit (not coming from source) \arg SelLocs is
|
||||
/// If the method is implicit (not coming from source) \p SelLocs is
|
||||
/// ignored.
|
||||
void setMethodParams(ASTContext &C,
|
||||
ArrayRef<ParmVarDecl*> Params,
|
||||
@ -403,8 +402,8 @@ class ObjCMethodDecl : public NamedDecl, public DeclContext {
|
||||
|
||||
bool isClassMethod() const { return !IsInstance; }
|
||||
|
||||
bool isSynthesized() const { return IsSynthesized; }
|
||||
void setSynthesized(bool isSynth) { IsSynthesized = isSynth; }
|
||||
bool isPropertyAccessor() const { return IsPropertyAccessor; }
|
||||
void setPropertyAccessor(bool isAccessor) { IsPropertyAccessor = isAccessor; }
|
||||
|
||||
bool isDefined() const { return IsDefined; }
|
||||
void setDefined(bool isDefined) { IsDefined = isDefined; }
|
||||
@ -418,7 +417,25 @@ class ObjCMethodDecl : public NamedDecl, public DeclContext {
|
||||
/// method in the interface or its categories.
|
||||
bool isOverriding() const { return IsOverriding; }
|
||||
void setOverriding(bool isOverriding) { IsOverriding = isOverriding; }
|
||||
|
||||
|
||||
/// \brief Return overridden methods for the given \p Method.
|
||||
///
|
||||
/// An ObjC method is considered to override any method in the class's
|
||||
/// base classes (and base's categories), its protocols, or its categories'
|
||||
/// protocols, that has
|
||||
/// the same selector and is of the same kind (class or instance).
|
||||
/// A method in an implementation is not considered as overriding the same
|
||||
/// method in the interface or its categories.
|
||||
void getOverriddenMethods(
|
||||
SmallVectorImpl<const ObjCMethodDecl *> &Overridden) const;
|
||||
|
||||
/// \brief Returns the property associated with this method's selector.
|
||||
///
|
||||
/// Note that even if this particular method is not marked as a property
|
||||
/// accessor, it is still possible for it to match a property declared in a
|
||||
/// superclass. Pass \c false if you only want to check the current class.
|
||||
const ObjCPropertyDecl *findPropertyDecl(bool CheckOverrides = true) const;
|
||||
|
||||
// Related to protocols declared in \@protocol
|
||||
void setDeclImplementation(ImplementationControl ic) {
|
||||
DeclImplementation = ic;
|
||||
@ -427,10 +444,15 @@ class ObjCMethodDecl : public NamedDecl, public DeclContext {
|
||||
return ImplementationControl(DeclImplementation);
|
||||
}
|
||||
|
||||
virtual Stmt *getBody() const {
|
||||
return (Stmt*) Body;
|
||||
}
|
||||
CompoundStmt *getCompoundBody() { return (CompoundStmt*)Body; }
|
||||
/// \brief Determine whether this method has a body.
|
||||
virtual bool hasBody() const { return Body; }
|
||||
|
||||
/// \brief Retrieve the body of this method, if it has one.
|
||||
virtual Stmt *getBody() const;
|
||||
|
||||
void setLazyBody(uint64_t Offset) { Body = Offset; }
|
||||
|
||||
CompoundStmt *getCompoundBody() { return (CompoundStmt*)getBody(); }
|
||||
void setBody(Stmt *B) { Body = B; }
|
||||
|
||||
/// \brief Returns whether this specific method is a definition.
|
||||
@ -438,7 +460,6 @@ class ObjCMethodDecl : public NamedDecl, public DeclContext {
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const ObjCMethodDecl *D) { return true; }
|
||||
static bool classofKind(Kind K) { return K == ObjCMethod; }
|
||||
static DeclContext *castToDeclContext(const ObjCMethodDecl *D) {
|
||||
return static_cast<DeclContext *>(const_cast<ObjCMethodDecl*>(D));
|
||||
@ -520,6 +541,13 @@ class ObjCContainerDecl : public NamedDecl, public DeclContext {
|
||||
|
||||
ObjCPropertyDecl *FindPropertyDeclaration(IdentifierInfo *PropertyId) const;
|
||||
|
||||
typedef llvm::DenseMap<IdentifierInfo*, ObjCPropertyDecl*> PropertyMap;
|
||||
|
||||
/// This routine collects list of properties to be implemented in the class.
|
||||
/// This includes, class's and its conforming protocols' properties.
|
||||
/// Note, the superclass's properties are not included in the list.
|
||||
virtual void collectPropertiesToImplement(PropertyMap &PM) const {}
|
||||
|
||||
SourceLocation getAtStartLoc() const { return AtStart; }
|
||||
void setAtStartLoc(SourceLocation Loc) { AtStart = Loc; }
|
||||
|
||||
@ -537,7 +565,6 @@ class ObjCContainerDecl : public NamedDecl, public DeclContext {
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const ObjCContainerDecl *D) { return true; }
|
||||
static bool classofKind(Kind K) {
|
||||
return K >= firstObjCContainer &&
|
||||
K <= lastObjCContainer;
|
||||
@ -880,6 +907,8 @@ class ObjCInterfaceDecl : public ObjCContainerDecl
|
||||
ObjCPropertyDecl
|
||||
*FindPropertyVisibleInPrimaryClass(IdentifierInfo *PropertyId) const;
|
||||
|
||||
virtual void collectPropertiesToImplement(PropertyMap &PM) const;
|
||||
|
||||
/// isSuperClassOf - Return true if this class is the specified class or is a
|
||||
/// super class of the specified interface class.
|
||||
bool isSuperClassOf(const ObjCInterfaceDecl *I) const {
|
||||
@ -992,7 +1021,6 @@ class ObjCInterfaceDecl : public ObjCContainerDecl
|
||||
void setTypeForDecl(const Type *TD) const { TypeForDecl = TD; }
|
||||
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const ObjCInterfaceDecl *D) { return true; }
|
||||
static bool classofKind(Kind K) { return K == ObjCInterface; }
|
||||
|
||||
friend class ASTReader;
|
||||
@ -1065,7 +1093,6 @@ class ObjCIvarDecl : public FieldDecl {
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const ObjCIvarDecl *D) { return true; }
|
||||
static bool classofKind(Kind K) { return K == ObjCIvar; }
|
||||
private:
|
||||
/// NextIvar - Next Ivar in the list of ivars declared in class; class's
|
||||
@ -1098,7 +1125,6 @@ class ObjCAtDefsFieldDecl : public FieldDecl {
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const ObjCAtDefsFieldDecl *D) { return true; }
|
||||
static bool classofKind(Kind K) { return K == ObjCAtDefsField; }
|
||||
};
|
||||
|
||||
@ -1277,8 +1303,9 @@ class ObjCProtocolDecl : public ObjCContainerDecl,
|
||||
return getFirstDeclaration();
|
||||
}
|
||||
|
||||
virtual void collectPropertiesToImplement(PropertyMap &PM) const;
|
||||
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const ObjCProtocolDecl *D) { return true; }
|
||||
static bool classofKind(Kind K) { return K == ObjCProtocol; }
|
||||
|
||||
friend class ASTReader;
|
||||
@ -1402,7 +1429,6 @@ class ObjCCategoryDecl : public ObjCContainerDecl {
|
||||
SourceLocation getIvarRBraceLoc() const { return IvarRBraceLoc; }
|
||||
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const ObjCCategoryDecl *D) { return true; }
|
||||
static bool classofKind(Kind K) { return K == ObjCCategory; }
|
||||
|
||||
friend class ASTDeclReader;
|
||||
@ -1455,7 +1481,6 @@ class ObjCImplDecl : public ObjCContainerDecl {
|
||||
}
|
||||
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const ObjCImplDecl *D) { return true; }
|
||||
static bool classofKind(Kind K) {
|
||||
return K >= firstObjCImpl && K <= lastObjCImpl;
|
||||
}
|
||||
@ -1532,7 +1557,6 @@ class ObjCCategoryImplDecl : public ObjCImplDecl {
|
||||
}
|
||||
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const ObjCCategoryImplDecl *D) { return true; }
|
||||
static bool classofKind(Kind K) { return K == ObjCCategoryImpl;}
|
||||
|
||||
friend class ASTDeclReader;
|
||||
@ -1568,8 +1592,12 @@ class ObjCImplementationDecl : public ObjCImplDecl {
|
||||
CXXCtorInitializer **IvarInitializers;
|
||||
unsigned NumIvarInitializers;
|
||||
|
||||
/// true if class has a .cxx_[construct,destruct] method.
|
||||
bool HasCXXStructors : 1;
|
||||
/// Do the ivars of this class require initialization other than
|
||||
/// zero-initialization?
|
||||
bool HasNonZeroConstructors : 1;
|
||||
|
||||
/// Do the ivars of this class require non-trivial destruction?
|
||||
bool HasDestructors : 1;
|
||||
|
||||
ObjCImplementationDecl(DeclContext *DC,
|
||||
ObjCInterfaceDecl *classInterface,
|
||||
@ -1581,7 +1609,7 @@ class ObjCImplementationDecl : public ObjCImplDecl {
|
||||
SuperClass(superDecl), IvarLBraceLoc(IvarLBraceLoc),
|
||||
IvarRBraceLoc(IvarRBraceLoc),
|
||||
IvarInitializers(0), NumIvarInitializers(0),
|
||||
HasCXXStructors(false) {}
|
||||
HasNonZeroConstructors(false), HasDestructors(false) {}
|
||||
public:
|
||||
static ObjCImplementationDecl *Create(ASTContext &C, DeclContext *DC,
|
||||
ObjCInterfaceDecl *classInterface,
|
||||
@ -1625,8 +1653,15 @@ class ObjCImplementationDecl : public ObjCImplDecl {
|
||||
CXXCtorInitializer ** initializers,
|
||||
unsigned numInitializers);
|
||||
|
||||
bool hasCXXStructors() const { return HasCXXStructors; }
|
||||
void setHasCXXStructors(bool val) { HasCXXStructors = val; }
|
||||
/// Do any of the ivars of this class (not counting its base classes)
|
||||
/// require construction other than zero-initialization?
|
||||
bool hasNonZeroConstructors() const { return HasNonZeroConstructors; }
|
||||
void setHasNonZeroConstructors(bool val) { HasNonZeroConstructors = val; }
|
||||
|
||||
/// Do any of the ivars of this class (not counting its base classes)
|
||||
/// require non-trivial destruction?
|
||||
bool hasDestructors() const { return HasDestructors; }
|
||||
void setHasDestructors(bool val) { HasDestructors = val; }
|
||||
|
||||
/// getIdentifier - Get the identifier that names the class
|
||||
/// interface associated with this implementation.
|
||||
@ -1676,7 +1711,6 @@ class ObjCImplementationDecl : public ObjCImplDecl {
|
||||
}
|
||||
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const ObjCImplementationDecl *D) { return true; }
|
||||
static bool classofKind(Kind K) { return K == ObjCImplementation; }
|
||||
|
||||
friend class ASTDeclReader;
|
||||
@ -1708,7 +1742,6 @@ class ObjCCompatibleAliasDecl : public NamedDecl {
|
||||
void setClassInterface(ObjCInterfaceDecl *D) { AliasedClass = D; }
|
||||
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const ObjCCompatibleAliasDecl *D) { return true; }
|
||||
static bool classofKind(Kind K) { return K == ObjCCompatibleAlias; }
|
||||
|
||||
};
|
||||
@ -1882,13 +1915,15 @@ class ObjCPropertyDecl : public NamedDecl {
|
||||
virtual SourceRange getSourceRange() const LLVM_READONLY {
|
||||
return SourceRange(AtLoc, getLocation());
|
||||
}
|
||||
|
||||
/// Get the default name of the synthesized ivar.
|
||||
IdentifierInfo *getDefaultSynthIvarName(ASTContext &Ctx) const;
|
||||
|
||||
/// Lookup a property by name in the specified DeclContext.
|
||||
static ObjCPropertyDecl *findPropertyDecl(const DeclContext *DC,
|
||||
IdentifierInfo *propertyID);
|
||||
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const ObjCPropertyDecl *D) { return true; }
|
||||
static bool classofKind(Kind K) { return K == ObjCProperty; }
|
||||
};
|
||||
|
||||
@ -1999,7 +2034,6 @@ class ObjCPropertyImplDecl : public Decl {
|
||||
}
|
||||
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const ObjCPropertyImplDecl *D) { return true; }
|
||||
static bool classofKind(Decl::Kind K) { return K == ObjCPropertyImpl; }
|
||||
|
||||
friend class ASTDeclReader;
|
||||
|
@ -50,7 +50,11 @@ class TemplateParameterList {
|
||||
|
||||
/// The number of template parameters in this template
|
||||
/// parameter list.
|
||||
unsigned NumParams;
|
||||
unsigned NumParams : 31;
|
||||
|
||||
/// Whether this template parameter list contains an unexpanded parameter
|
||||
/// pack.
|
||||
unsigned ContainsUnexpandedParameterPack : 1;
|
||||
|
||||
protected:
|
||||
TemplateParameterList(SourceLocation TemplateLoc, SourceLocation LAngleLoc,
|
||||
@ -104,6 +108,12 @@ class TemplateParameterList {
|
||||
/// the second template parameter list will have depth 1, etc.
|
||||
unsigned getDepth() const;
|
||||
|
||||
/// \brief Determine whether this template parameter list contains an
|
||||
/// unexpanded parameter pack.
|
||||
bool containsUnexpandedParameterPack() const {
|
||||
return ContainsUnexpandedParameterPack;
|
||||
}
|
||||
|
||||
SourceLocation getTemplateLoc() const { return TemplateLoc; }
|
||||
SourceLocation getLAngleLoc() const { return LAngleLoc; }
|
||||
SourceLocation getRAngleLoc() const { return RAngleLoc; }
|
||||
@ -139,8 +149,8 @@ class TemplateArgumentList {
|
||||
/// argument list.
|
||||
unsigned NumArguments;
|
||||
|
||||
TemplateArgumentList(const TemplateArgumentList &Other); // DO NOT IMPL
|
||||
void operator=(const TemplateArgumentList &Other); // DO NOT IMPL
|
||||
TemplateArgumentList(const TemplateArgumentList &Other) LLVM_DELETED_FUNCTION;
|
||||
void operator=(const TemplateArgumentList &Other) LLVM_DELETED_FUNCTION;
|
||||
|
||||
TemplateArgumentList(const TemplateArgument *Args, unsigned NumArgs,
|
||||
bool Owned)
|
||||
@ -233,12 +243,6 @@ class TemplateDecl : public NamedDecl {
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const TemplateDecl *D) { return true; }
|
||||
static bool classof(const RedeclarableTemplateDecl *D) { return true; }
|
||||
static bool classof(const FunctionTemplateDecl *D) { return true; }
|
||||
static bool classof(const ClassTemplateDecl *D) { return true; }
|
||||
static bool classof(const TemplateTemplateParmDecl *D) { return true; }
|
||||
static bool classof(const TypeAliasTemplateDecl *D) { return true; }
|
||||
static bool classofKind(Kind K) {
|
||||
return K >= firstTemplate && K <= lastTemplate;
|
||||
}
|
||||
@ -678,10 +682,6 @@ class RedeclarableTemplateDecl : public TemplateDecl,
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const RedeclarableTemplateDecl *D) { return true; }
|
||||
static bool classof(const FunctionTemplateDecl *D) { return true; }
|
||||
static bool classof(const ClassTemplateDecl *D) { return true; }
|
||||
static bool classof(const TypeAliasTemplateDecl *D) { return true; }
|
||||
static bool classofKind(Kind K) {
|
||||
return K >= firstRedeclarableTemplate && K <= lastRedeclarableTemplate;
|
||||
}
|
||||
@ -827,7 +827,6 @@ class FunctionTemplateDecl : public RedeclarableTemplateDecl {
|
||||
|
||||
// Implement isa/cast/dyncast support
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const FunctionTemplateDecl *D) { return true; }
|
||||
static bool classofKind(Kind K) { return K == FunctionTemplate; }
|
||||
|
||||
friend class ASTDeclReader;
|
||||
@ -969,7 +968,6 @@ class TemplateTypeParmDecl : public TypeDecl {
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const TemplateTypeParmDecl *D) { return true; }
|
||||
static bool classofKind(Kind K) { return K == TemplateTypeParm; }
|
||||
};
|
||||
|
||||
@ -1090,8 +1088,17 @@ class NonTypeTemplateParmDecl
|
||||
/// \endcode
|
||||
bool isParameterPack() const { return ParameterPack; }
|
||||
|
||||
/// \brief Whether this parameter pack is a pack expansion.
|
||||
///
|
||||
/// A non-type template parameter pack is a pack expansion if its type
|
||||
/// contains an unexpanded parameter pack. In this case, we will have
|
||||
/// built a PackExpansionType wrapping the type.
|
||||
bool isPackExpansion() const {
|
||||
return ParameterPack && getType()->getAs<PackExpansionType>();
|
||||
}
|
||||
|
||||
/// \brief Whether this parameter is a non-type template parameter pack
|
||||
/// that has different types at different positions.
|
||||
/// that has a known list of different types at different positions.
|
||||
///
|
||||
/// A parameter pack is an expanded parameter pack when the original
|
||||
/// parameter pack's type was itself a pack expansion, and that expansion
|
||||
@ -1141,7 +1148,6 @@ class NonTypeTemplateParmDecl
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const NonTypeTemplateParmDecl *D) { return true; }
|
||||
static bool classofKind(Kind K) { return K == NonTypeTemplateParm; }
|
||||
};
|
||||
|
||||
@ -1165,23 +1171,47 @@ class TemplateTemplateParmDecl : public TemplateDecl,
|
||||
/// \brief Whether this parameter is a parameter pack.
|
||||
bool ParameterPack;
|
||||
|
||||
/// \brief Whether this template template parameter is an "expanded"
|
||||
/// parameter pack, meaning that it is a pack expansion and we
|
||||
/// already know the set of template parameters that expansion expands to.
|
||||
bool ExpandedParameterPack;
|
||||
|
||||
/// \brief The number of parameters in an expanded parameter pack.
|
||||
unsigned NumExpandedParams;
|
||||
|
||||
TemplateTemplateParmDecl(DeclContext *DC, SourceLocation L,
|
||||
unsigned D, unsigned P, bool ParameterPack,
|
||||
IdentifierInfo *Id, TemplateParameterList *Params)
|
||||
: TemplateDecl(TemplateTemplateParm, DC, L, Id, Params),
|
||||
TemplateParmPosition(D, P), DefaultArgument(),
|
||||
DefaultArgumentWasInherited(false), ParameterPack(ParameterPack)
|
||||
DefaultArgumentWasInherited(false), ParameterPack(ParameterPack),
|
||||
ExpandedParameterPack(false), NumExpandedParams(0)
|
||||
{ }
|
||||
|
||||
TemplateTemplateParmDecl(DeclContext *DC, SourceLocation L,
|
||||
unsigned D, unsigned P,
|
||||
IdentifierInfo *Id, TemplateParameterList *Params,
|
||||
unsigned NumExpansions,
|
||||
TemplateParameterList * const *Expansions);
|
||||
|
||||
public:
|
||||
static TemplateTemplateParmDecl *Create(const ASTContext &C, DeclContext *DC,
|
||||
SourceLocation L, unsigned D,
|
||||
unsigned P, bool ParameterPack,
|
||||
IdentifierInfo *Id,
|
||||
TemplateParameterList *Params);
|
||||
static TemplateTemplateParmDecl *Create(const ASTContext &C, DeclContext *DC,
|
||||
SourceLocation L, unsigned D,
|
||||
unsigned P,
|
||||
IdentifierInfo *Id,
|
||||
TemplateParameterList *Params,
|
||||
llvm::ArrayRef<TemplateParameterList*> Expansions);
|
||||
|
||||
static TemplateTemplateParmDecl *CreateDeserialized(ASTContext &C,
|
||||
static TemplateTemplateParmDecl *CreateDeserialized(ASTContext &C,
|
||||
unsigned ID);
|
||||
static TemplateTemplateParmDecl *CreateDeserialized(ASTContext &C,
|
||||
unsigned ID,
|
||||
unsigned NumExpansions);
|
||||
|
||||
using TemplateParmPosition::getDepth;
|
||||
using TemplateParmPosition::getPosition;
|
||||
@ -1195,6 +1225,49 @@ class TemplateTemplateParmDecl : public TemplateDecl,
|
||||
/// \endcode
|
||||
bool isParameterPack() const { return ParameterPack; }
|
||||
|
||||
/// \brief Whether this parameter pack is a pack expansion.
|
||||
///
|
||||
/// A template template parameter pack is a pack expansion if its template
|
||||
/// parameter list contains an unexpanded parameter pack.
|
||||
bool isPackExpansion() const {
|
||||
return ParameterPack &&
|
||||
getTemplateParameters()->containsUnexpandedParameterPack();
|
||||
}
|
||||
|
||||
/// \brief Whether this parameter is a template template parameter pack that
|
||||
/// has a known list of different template parameter lists at different
|
||||
/// positions.
|
||||
///
|
||||
/// A parameter pack is an expanded parameter pack when the original parameter
|
||||
/// pack's template parameter list was itself a pack expansion, and that
|
||||
/// expansion has already been expanded. For exampe, given:
|
||||
///
|
||||
/// \code
|
||||
/// template<typename...Types> struct Outer {
|
||||
/// template<template<Types> class...Templates> struct Inner;
|
||||
/// };
|
||||
/// \endcode
|
||||
///
|
||||
/// The parameter pack \c Templates is a pack expansion, which expands the
|
||||
/// pack \c Types. When \c Types is supplied with template arguments by
|
||||
/// instantiating \c Outer, the instantiation of \c Templates is an expanded
|
||||
/// parameter pack.
|
||||
bool isExpandedParameterPack() const { return ExpandedParameterPack; }
|
||||
|
||||
/// \brief Retrieves the number of expansion template parameters in
|
||||
/// an expanded parameter pack.
|
||||
unsigned getNumExpansionTemplateParameters() const {
|
||||
assert(ExpandedParameterPack && "Not an expansion parameter pack");
|
||||
return NumExpandedParams;
|
||||
}
|
||||
|
||||
/// \brief Retrieve a particular expansion type within an expanded parameter
|
||||
/// pack.
|
||||
TemplateParameterList *getExpansionTemplateParameters(unsigned I) const {
|
||||
assert(I < NumExpandedParams && "Out-of-range expansion type index");
|
||||
return reinterpret_cast<TemplateParameterList *const *>(this + 1)[I];
|
||||
}
|
||||
|
||||
/// \brief Determine whether this template parameter has a default
|
||||
/// argument.
|
||||
bool hasDefaultArgument() const {
|
||||
@ -1238,7 +1311,6 @@ class TemplateTemplateParmDecl : public TemplateDecl,
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const TemplateTemplateParmDecl *D) { return true; }
|
||||
static bool classofKind(Kind K) { return K == TemplateTemplateParm; }
|
||||
|
||||
friend class ASTDeclReader;
|
||||
@ -1505,14 +1577,6 @@ class ClassTemplateSpecializationDecl
|
||||
K <= lastClassTemplateSpecialization;
|
||||
}
|
||||
|
||||
static bool classof(const ClassTemplateSpecializationDecl *) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool classof(const ClassTemplatePartialSpecializationDecl *) {
|
||||
return true;
|
||||
}
|
||||
|
||||
friend class ASTDeclReader;
|
||||
friend class ASTDeclWriter;
|
||||
};
|
||||
@ -1681,10 +1745,6 @@ class ClassTemplatePartialSpecializationDecl
|
||||
return K == ClassTemplatePartialSpecialization;
|
||||
}
|
||||
|
||||
static bool classof(const ClassTemplatePartialSpecializationDecl *) {
|
||||
return true;
|
||||
}
|
||||
|
||||
friend class ASTDeclReader;
|
||||
friend class ASTDeclWriter;
|
||||
};
|
||||
@ -1886,7 +1946,6 @@ class ClassTemplateDecl : public RedeclarableTemplateDecl {
|
||||
|
||||
// Implement isa/cast/dyncast support
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const ClassTemplateDecl *D) { return true; }
|
||||
static bool classofKind(Kind K) { return K == ClassTemplate; }
|
||||
|
||||
friend class ASTDeclReader;
|
||||
@ -1984,7 +2043,6 @@ class FriendTemplateDecl : public Decl {
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classofKind(Kind K) { return K == Decl::FriendTemplate; }
|
||||
static bool classof(const FriendTemplateDecl *D) { return true; }
|
||||
|
||||
friend class ASTDeclReader;
|
||||
};
|
||||
@ -2059,7 +2117,6 @@ class TypeAliasTemplateDecl : public RedeclarableTemplateDecl {
|
||||
|
||||
// Implement isa/cast/dyncast support
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const TypeAliasTemplateDecl *D) { return true; }
|
||||
static bool classofKind(Kind K) { return K == TypeAliasTemplate; }
|
||||
|
||||
friend class ASTDeclReader;
|
||||
@ -2123,9 +2180,6 @@ class ClassScopeFunctionSpecializationDecl : public Decl {
|
||||
static bool classofKind(Kind K) {
|
||||
return K == Decl::ClassScopeFunctionSpecialization;
|
||||
}
|
||||
static bool classof(const ClassScopeFunctionSpecializationDecl *D) {
|
||||
return true;
|
||||
}
|
||||
|
||||
friend class ASTDeclReader;
|
||||
friend class ASTDeclWriter;
|
||||
|
@ -334,8 +334,8 @@ class DeclarationNameTable {
|
||||
CXXOperatorIdName *CXXOperatorNames; // Operator names
|
||||
void *CXXLiteralOperatorNames; // Actually a CXXOperatorIdName*
|
||||
|
||||
DeclarationNameTable(const DeclarationNameTable&); // NONCOPYABLE
|
||||
DeclarationNameTable& operator=(const DeclarationNameTable&); // NONCOPYABLE
|
||||
DeclarationNameTable(const DeclarationNameTable&) LLVM_DELETED_FUNCTION;
|
||||
void operator=(const DeclarationNameTable&) LLVM_DELETED_FUNCTION;
|
||||
|
||||
public:
|
||||
DeclarationNameTable(const ASTContext &C);
|
||||
|
@ -34,6 +34,7 @@
|
||||
namespace clang {
|
||||
class ASTContext;
|
||||
class APValue;
|
||||
class CastExpr;
|
||||
class Decl;
|
||||
class IdentifierInfo;
|
||||
class ParmVarDecl;
|
||||
@ -42,6 +43,7 @@ namespace clang {
|
||||
class BlockDecl;
|
||||
class CXXBaseSpecifier;
|
||||
class CXXOperatorCallExpr;
|
||||
class MaterializeTemporaryExpr;
|
||||
class CXXMemberCallExpr;
|
||||
class ObjCPropertyRefExpr;
|
||||
class OpaqueValueExpr;
|
||||
@ -49,6 +51,48 @@ namespace clang {
|
||||
/// \brief A simple array of base specifiers.
|
||||
typedef SmallVector<CXXBaseSpecifier*, 4> CXXCastPath;
|
||||
|
||||
/// \brief An adjustment to be made to the temporary created when emitting a
|
||||
/// reference binding, which accesses a particular subobject of that temporary.
|
||||
struct SubobjectAdjustment {
|
||||
enum {
|
||||
DerivedToBaseAdjustment,
|
||||
FieldAdjustment,
|
||||
MemberPointerAdjustment
|
||||
} Kind;
|
||||
|
||||
union {
|
||||
struct {
|
||||
const CastExpr *BasePath;
|
||||
const CXXRecordDecl *DerivedClass;
|
||||
} DerivedToBase;
|
||||
|
||||
FieldDecl *Field;
|
||||
|
||||
struct {
|
||||
const MemberPointerType *MPT;
|
||||
Expr *RHS;
|
||||
} Ptr;
|
||||
};
|
||||
|
||||
SubobjectAdjustment(const CastExpr *BasePath,
|
||||
const CXXRecordDecl *DerivedClass)
|
||||
: Kind(DerivedToBaseAdjustment) {
|
||||
DerivedToBase.BasePath = BasePath;
|
||||
DerivedToBase.DerivedClass = DerivedClass;
|
||||
}
|
||||
|
||||
SubobjectAdjustment(FieldDecl *Field)
|
||||
: Kind(FieldAdjustment) {
|
||||
this->Field = Field;
|
||||
}
|
||||
|
||||
SubobjectAdjustment(const MemberPointerType *MPT, Expr *RHS)
|
||||
: Kind(MemberPointerAdjustment) {
|
||||
this->Ptr.MPT = MPT;
|
||||
this->Ptr.RHS = RHS;
|
||||
}
|
||||
};
|
||||
|
||||
/// Expr - This represents one expression. Note that Expr's are subclasses of
|
||||
/// Stmt. This allows an expression to be transparently used any place a Stmt
|
||||
/// is required.
|
||||
@ -220,15 +264,6 @@ class Expr : public Stmt {
|
||||
/// Reasons why an expression might not be an l-value.
|
||||
LValueClassification ClassifyLValue(ASTContext &Ctx) const;
|
||||
|
||||
/// isModifiableLvalue - C99 6.3.2.1: an lvalue that does not have array type,
|
||||
/// does not have an incomplete type, does not have a const-qualified type,
|
||||
/// and if it is a structure or union, does not have any member (including,
|
||||
/// recursively, any member or element of all contained aggregates or unions)
|
||||
/// with a const-qualified type.
|
||||
///
|
||||
/// \param Loc [in,out] - A source location which *may* be filled
|
||||
/// in with the location of the expression making this a
|
||||
/// non-modifiable lvalue, if specified.
|
||||
enum isModifiableLvalueResult {
|
||||
MLV_Valid,
|
||||
MLV_NotObjectType,
|
||||
@ -247,6 +282,15 @@ class Expr : public Stmt {
|
||||
MLV_ClassTemporary,
|
||||
MLV_ArrayTemporary
|
||||
};
|
||||
/// isModifiableLvalue - C99 6.3.2.1: an lvalue that does not have array type,
|
||||
/// does not have an incomplete type, does not have a const-qualified type,
|
||||
/// and if it is a structure or union, does not have any member (including,
|
||||
/// recursively, any member or element of all contained aggregates or unions)
|
||||
/// with a const-qualified type.
|
||||
///
|
||||
/// \param Loc [in,out] - A source location which *may* be filled
|
||||
/// in with the location of the expression making this a
|
||||
/// non-modifiable lvalue, if specified.
|
||||
isModifiableLvalueResult isModifiableLvalue(ASTContext &Ctx,
|
||||
SourceLocation *Loc = 0) const;
|
||||
|
||||
@ -392,6 +436,9 @@ class Expr : public Stmt {
|
||||
/// property, find the underlying property reference expression.
|
||||
const ObjCPropertyRefExpr *getObjCProperty() const;
|
||||
|
||||
/// \brief Check if this expression is the ObjC 'self' implicit parameter.
|
||||
bool isObjCSelfExpr() const;
|
||||
|
||||
/// \brief Returns whether this expression refers to a vector element.
|
||||
bool refersToVectorElement() const;
|
||||
|
||||
@ -692,11 +739,22 @@ class Expr : public Stmt {
|
||||
/// behavior if the object isn't dynamically of the derived type.
|
||||
const CXXRecordDecl *getBestDynamicClassType() const;
|
||||
|
||||
/// Walk outwards from an expression we want to bind a reference to and
|
||||
/// find the expression whose lifetime needs to be extended. Record
|
||||
/// the adjustments needed along the path.
|
||||
const Expr *
|
||||
skipRValueSubobjectAdjustments(
|
||||
SmallVectorImpl<SubobjectAdjustment> &Adjustments) const;
|
||||
|
||||
/// Skip irrelevant expressions to find what should be materialize for
|
||||
/// binding with a reference.
|
||||
const Expr *
|
||||
findMaterializedTemporary(const MaterializeTemporaryExpr *&MTE) const;
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() >= firstExprConstant &&
|
||||
T->getStmtClass() <= lastExprConstant;
|
||||
}
|
||||
static bool classof(const Expr *) { return true; }
|
||||
};
|
||||
|
||||
|
||||
@ -762,7 +820,6 @@ class OpaqueValueExpr : public Expr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == OpaqueValueExprClass;
|
||||
}
|
||||
static bool classof(const OpaqueValueExpr *) { return true; }
|
||||
};
|
||||
|
||||
/// \brief A reference to a declared variable, function, enum, etc.
|
||||
@ -1059,7 +1116,6 @@ class DeclRefExpr : public Expr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == DeclRefExprClass;
|
||||
}
|
||||
static bool classof(const DeclRefExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() { return child_range(); }
|
||||
@ -1109,7 +1165,6 @@ class PredefinedExpr : public Expr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == PredefinedExprClass;
|
||||
}
|
||||
static bool classof(const PredefinedExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() { return child_range(); }
|
||||
@ -1132,8 +1187,8 @@ class APNumericStorage {
|
||||
|
||||
bool hasAllocation() const { return llvm::APInt::getNumWords(BitWidth) > 1; }
|
||||
|
||||
APNumericStorage(const APNumericStorage&); // do not implement
|
||||
APNumericStorage& operator=(const APNumericStorage&); // do not implement
|
||||
APNumericStorage(const APNumericStorage &) LLVM_DELETED_FUNCTION;
|
||||
void operator=(const APNumericStorage &) LLVM_DELETED_FUNCTION;
|
||||
|
||||
protected:
|
||||
APNumericStorage() : VAL(0), BitWidth(0) { }
|
||||
@ -1196,7 +1251,6 @@ class IntegerLiteral : public Expr, public APIntStorage {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == IntegerLiteralClass;
|
||||
}
|
||||
static bool classof(const IntegerLiteral *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() { return child_range(); }
|
||||
@ -1243,7 +1297,6 @@ class CharacterLiteral : public Expr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CharacterLiteralClass;
|
||||
}
|
||||
static bool classof(const CharacterLiteral *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() { return child_range(); }
|
||||
@ -1286,7 +1339,6 @@ class FloatingLiteral : public Expr, private APFloatStorage {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == FloatingLiteralClass;
|
||||
}
|
||||
static bool classof(const FloatingLiteral *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() { return child_range(); }
|
||||
@ -1317,7 +1369,6 @@ class ImaginaryLiteral : public Expr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ImaginaryLiteralClass;
|
||||
}
|
||||
static bool classof(const ImaginaryLiteral *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() { return child_range(&Val, &Val+1); }
|
||||
@ -1479,7 +1530,6 @@ class StringLiteral : public Expr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == StringLiteralClass;
|
||||
}
|
||||
static bool classof(const StringLiteral *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() { return child_range(); }
|
||||
@ -1520,7 +1570,6 @@ class ParenExpr : public Expr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ParenExprClass;
|
||||
}
|
||||
static bool classof(const ParenExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() { return child_range(&Val, &Val+1); }
|
||||
@ -1610,7 +1659,7 @@ class UnaryOperator : public Expr {
|
||||
|
||||
/// getOpcodeStr - Turn an Opcode enum value into the punctuation char it
|
||||
/// corresponds to, e.g. "sizeof" or "[pre]++"
|
||||
static const char *getOpcodeStr(Opcode Op);
|
||||
static StringRef getOpcodeStr(Opcode Op);
|
||||
|
||||
/// \brief Retrieve the unary opcode that corresponds to the given
|
||||
/// overloaded operator.
|
||||
@ -1631,7 +1680,6 @@ class UnaryOperator : public Expr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == UnaryOperatorClass;
|
||||
}
|
||||
static bool classof(const UnaryOperator *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() { return child_range(&Val, &Val+1); }
|
||||
@ -1757,8 +1805,7 @@ class OffsetOfExpr : public Expr {
|
||||
|
||||
OffsetOfExpr(ASTContext &C, QualType type,
|
||||
SourceLocation OperatorLoc, TypeSourceInfo *tsi,
|
||||
OffsetOfNode* compsPtr, unsigned numComps,
|
||||
Expr** exprsPtr, unsigned numExprs,
|
||||
ArrayRef<OffsetOfNode> comps, ArrayRef<Expr*> exprs,
|
||||
SourceLocation RParenLoc);
|
||||
|
||||
explicit OffsetOfExpr(unsigned numComps, unsigned numExprs)
|
||||
@ -1769,9 +1816,8 @@ class OffsetOfExpr : public Expr {
|
||||
|
||||
static OffsetOfExpr *Create(ASTContext &C, QualType type,
|
||||
SourceLocation OperatorLoc, TypeSourceInfo *tsi,
|
||||
OffsetOfNode* compsPtr, unsigned numComps,
|
||||
Expr** exprsPtr, unsigned numExprs,
|
||||
SourceLocation RParenLoc);
|
||||
ArrayRef<OffsetOfNode> comps,
|
||||
ArrayRef<Expr*> exprs, SourceLocation RParenLoc);
|
||||
|
||||
static OffsetOfExpr *CreateEmpty(ASTContext &C,
|
||||
unsigned NumComps, unsigned NumExprs);
|
||||
@ -1832,8 +1878,6 @@ class OffsetOfExpr : public Expr {
|
||||
return T->getStmtClass() == OffsetOfExprClass;
|
||||
}
|
||||
|
||||
static bool classof(const OffsetOfExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() {
|
||||
Stmt **begin =
|
||||
@ -1937,7 +1981,6 @@ class UnaryExprOrTypeTraitExpr : public Expr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == UnaryExprOrTypeTraitExprClass;
|
||||
}
|
||||
static bool classof(const UnaryExprOrTypeTraitExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children();
|
||||
@ -2017,7 +2060,6 @@ class ArraySubscriptExpr : public Expr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ArraySubscriptExprClass;
|
||||
}
|
||||
static bool classof(const ArraySubscriptExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() {
|
||||
@ -2041,7 +2083,7 @@ class CallExpr : public Expr {
|
||||
protected:
|
||||
// These versions of the constructor are for derived classes.
|
||||
CallExpr(ASTContext& C, StmtClass SC, Expr *fn, unsigned NumPreArgs,
|
||||
Expr **args, unsigned numargs, QualType t, ExprValueKind VK,
|
||||
ArrayRef<Expr*> args, QualType t, ExprValueKind VK,
|
||||
SourceLocation rparenloc);
|
||||
CallExpr(ASTContext &C, StmtClass SC, unsigned NumPreArgs, EmptyShell Empty);
|
||||
|
||||
@ -2061,7 +2103,7 @@ class CallExpr : public Expr {
|
||||
unsigned getNumPreArgs() const { return CallExprBits.NumPreArgs; }
|
||||
|
||||
public:
|
||||
CallExpr(ASTContext& C, Expr *fn, Expr **args, unsigned numargs, QualType t,
|
||||
CallExpr(ASTContext& C, Expr *fn, ArrayRef<Expr*> args, QualType t,
|
||||
ExprValueKind VK, SourceLocation rparenloc);
|
||||
|
||||
/// \brief Build an empty call expression.
|
||||
@ -2153,7 +2195,6 @@ class CallExpr : public Expr {
|
||||
return T->getStmtClass() >= firstCallExprConstant &&
|
||||
T->getStmtClass() <= lastCallExprConstant;
|
||||
}
|
||||
static bool classof(const CallExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() {
|
||||
@ -2440,7 +2481,6 @@ class MemberExpr : public Expr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == MemberExprClass;
|
||||
}
|
||||
static bool classof(const MemberExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() { return child_range(&Base, &Base+1); }
|
||||
@ -2506,7 +2546,6 @@ class CompoundLiteralExpr : public Expr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CompoundLiteralExprClass;
|
||||
}
|
||||
static bool classof(const CompoundLiteralExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() { return child_range(&Init, &Init+1); }
|
||||
@ -2597,7 +2636,6 @@ class CastExpr : public Expr {
|
||||
return T->getStmtClass() >= firstCastExprConstant &&
|
||||
T->getStmtClass() <= lastCastExprConstant;
|
||||
}
|
||||
static bool classof(const CastExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() { return child_range(&Op, &Op+1); }
|
||||
@ -2661,7 +2699,6 @@ class ImplicitCastExpr : public CastExpr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ImplicitCastExprClass;
|
||||
}
|
||||
static bool classof(const ImplicitCastExpr *) { return true; }
|
||||
};
|
||||
|
||||
inline Expr *Expr::IgnoreImpCasts() {
|
||||
@ -2716,7 +2753,6 @@ class ExplicitCastExpr : public CastExpr {
|
||||
return T->getStmtClass() >= firstExplicitCastExprConstant &&
|
||||
T->getStmtClass() <= lastExplicitCastExprConstant;
|
||||
}
|
||||
static bool classof(const ExplicitCastExpr *) { return true; }
|
||||
};
|
||||
|
||||
/// CStyleCastExpr - An explicit cast in C (C99 6.5.4) or a C-style
|
||||
@ -2757,7 +2793,6 @@ class CStyleCastExpr : public ExplicitCastExpr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CStyleCastExprClass;
|
||||
}
|
||||
static bool classof(const CStyleCastExpr *) { return true; }
|
||||
};
|
||||
|
||||
/// \brief A builtin binary operation expression such as "x + y" or "x <= y".
|
||||
@ -2784,6 +2819,12 @@ class BinaryOperator : public Expr {
|
||||
|
||||
private:
|
||||
unsigned Opc : 6;
|
||||
|
||||
// Records the FP_CONTRACT pragma status at the point that this binary
|
||||
// operator was parsed. This bit is only meaningful for operations on
|
||||
// floating point types. For all other types it should default to
|
||||
// false.
|
||||
unsigned FPContractable : 1;
|
||||
SourceLocation OpLoc;
|
||||
|
||||
enum { LHS, RHS, END_EXPR };
|
||||
@ -2792,7 +2833,7 @@ class BinaryOperator : public Expr {
|
||||
|
||||
BinaryOperator(Expr *lhs, Expr *rhs, Opcode opc, QualType ResTy,
|
||||
ExprValueKind VK, ExprObjectKind OK,
|
||||
SourceLocation opLoc)
|
||||
SourceLocation opLoc, bool fpContractable)
|
||||
: Expr(BinaryOperatorClass, ResTy, VK, OK,
|
||||
lhs->isTypeDependent() || rhs->isTypeDependent(),
|
||||
lhs->isValueDependent() || rhs->isValueDependent(),
|
||||
@ -2800,7 +2841,7 @@ class BinaryOperator : public Expr {
|
||||
rhs->isInstantiationDependent()),
|
||||
(lhs->containsUnexpandedParameterPack() ||
|
||||
rhs->containsUnexpandedParameterPack())),
|
||||
Opc(opc), OpLoc(opLoc) {
|
||||
Opc(opc), FPContractable(fpContractable), OpLoc(opLoc) {
|
||||
SubExprs[LHS] = lhs;
|
||||
SubExprs[RHS] = rhs;
|
||||
assert(!isCompoundAssignmentOp() &&
|
||||
@ -2829,9 +2870,9 @@ class BinaryOperator : public Expr {
|
||||
|
||||
/// getOpcodeStr - Turn an Opcode enum value into the punctuation char it
|
||||
/// corresponds to, e.g. "<<=".
|
||||
static const char *getOpcodeStr(Opcode Op);
|
||||
static StringRef getOpcodeStr(Opcode Op);
|
||||
|
||||
const char *getOpcodeStr() const { return getOpcodeStr(getOpcode()); }
|
||||
StringRef getOpcodeStr() const { return getOpcodeStr(getOpcode()); }
|
||||
|
||||
/// \brief Retrieve the binary opcode that corresponds to the given
|
||||
/// overloaded operator.
|
||||
@ -2894,17 +2935,24 @@ class BinaryOperator : public Expr {
|
||||
return S->getStmtClass() >= firstBinaryOperatorConstant &&
|
||||
S->getStmtClass() <= lastBinaryOperatorConstant;
|
||||
}
|
||||
static bool classof(const BinaryOperator *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() {
|
||||
return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR);
|
||||
}
|
||||
|
||||
// Set the FP contractability status of this operator. Only meaningful for
|
||||
// operations on floating point types.
|
||||
void setFPContractable(bool FPC) { FPContractable = FPC; }
|
||||
|
||||
// Get the FP contractability status of this operator. Only meaningful for
|
||||
// operations on floating point types.
|
||||
bool isFPContractable() const { return FPContractable; }
|
||||
|
||||
protected:
|
||||
BinaryOperator(Expr *lhs, Expr *rhs, Opcode opc, QualType ResTy,
|
||||
ExprValueKind VK, ExprObjectKind OK,
|
||||
SourceLocation opLoc, bool dead)
|
||||
SourceLocation opLoc, bool fpContractable, bool dead2)
|
||||
: Expr(CompoundAssignOperatorClass, ResTy, VK, OK,
|
||||
lhs->isTypeDependent() || rhs->isTypeDependent(),
|
||||
lhs->isValueDependent() || rhs->isValueDependent(),
|
||||
@ -2912,7 +2960,7 @@ class BinaryOperator : public Expr {
|
||||
rhs->isInstantiationDependent()),
|
||||
(lhs->containsUnexpandedParameterPack() ||
|
||||
rhs->containsUnexpandedParameterPack())),
|
||||
Opc(opc), OpLoc(opLoc) {
|
||||
Opc(opc), FPContractable(fpContractable), OpLoc(opLoc) {
|
||||
SubExprs[LHS] = lhs;
|
||||
SubExprs[RHS] = rhs;
|
||||
}
|
||||
@ -2934,8 +2982,9 @@ class CompoundAssignOperator : public BinaryOperator {
|
||||
CompoundAssignOperator(Expr *lhs, Expr *rhs, Opcode opc, QualType ResType,
|
||||
ExprValueKind VK, ExprObjectKind OK,
|
||||
QualType CompLHSType, QualType CompResultType,
|
||||
SourceLocation OpLoc)
|
||||
: BinaryOperator(lhs, rhs, opc, ResType, VK, OK, OpLoc, true),
|
||||
SourceLocation OpLoc, bool fpContractable)
|
||||
: BinaryOperator(lhs, rhs, opc, ResType, VK, OK, OpLoc, fpContractable,
|
||||
true),
|
||||
ComputationLHSType(CompLHSType),
|
||||
ComputationResultType(CompResultType) {
|
||||
assert(isCompoundAssignmentOp() &&
|
||||
@ -2955,7 +3004,6 @@ class CompoundAssignOperator : public BinaryOperator {
|
||||
QualType getComputationResultType() const { return ComputationResultType; }
|
||||
void setComputationResultType(QualType T) { ComputationResultType = T; }
|
||||
|
||||
static bool classof(const CompoundAssignOperator *) { return true; }
|
||||
static bool classof(const Stmt *S) {
|
||||
return S->getStmtClass() == CompoundAssignOperatorClass;
|
||||
}
|
||||
@ -3001,7 +3049,6 @@ class AbstractConditionalOperator : public Expr {
|
||||
return T->getStmtClass() == ConditionalOperatorClass ||
|
||||
T->getStmtClass() == BinaryConditionalOperatorClass;
|
||||
}
|
||||
static bool classof(const AbstractConditionalOperator *) { return true; }
|
||||
};
|
||||
|
||||
/// ConditionalOperator - The ?: ternary operator. The GNU "missing
|
||||
@ -3060,7 +3107,6 @@ class ConditionalOperator : public AbstractConditionalOperator {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ConditionalOperatorClass;
|
||||
}
|
||||
static bool classof(const ConditionalOperator *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() {
|
||||
@ -3142,7 +3188,6 @@ class BinaryConditionalOperator : public AbstractConditionalOperator {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == BinaryConditionalOperatorClass;
|
||||
}
|
||||
static bool classof(const BinaryConditionalOperator *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() {
|
||||
@ -3198,7 +3243,6 @@ class AddrLabelExpr : public Expr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == AddrLabelExprClass;
|
||||
}
|
||||
static bool classof(const AddrLabelExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() { return child_range(); }
|
||||
@ -3242,7 +3286,6 @@ class StmtExpr : public Expr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == StmtExprClass;
|
||||
}
|
||||
static bool classof(const StmtExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() { return child_range(&SubStmt, &SubStmt+1); }
|
||||
@ -3266,9 +3309,8 @@ class ShuffleVectorExpr : public Expr {
|
||||
unsigned NumExprs;
|
||||
|
||||
public:
|
||||
ShuffleVectorExpr(ASTContext &C, Expr **args, unsigned nexpr,
|
||||
QualType Type, SourceLocation BLoc,
|
||||
SourceLocation RP);
|
||||
ShuffleVectorExpr(ASTContext &C, ArrayRef<Expr*> args, QualType Type,
|
||||
SourceLocation BLoc, SourceLocation RP);
|
||||
|
||||
/// \brief Build an empty vector-shuffle expression.
|
||||
explicit ShuffleVectorExpr(EmptyShell Empty)
|
||||
@ -3286,7 +3328,6 @@ class ShuffleVectorExpr : public Expr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ShuffleVectorExprClass;
|
||||
}
|
||||
static bool classof(const ShuffleVectorExpr *) { return true; }
|
||||
|
||||
/// getNumSubExprs - Return the size of the SubExprs array. This includes the
|
||||
/// constant expression, the actual arguments passed in, and the function
|
||||
@ -3308,7 +3349,7 @@ class ShuffleVectorExpr : public Expr {
|
||||
|
||||
void setExprs(ASTContext &C, Expr ** Exprs, unsigned NumExprs);
|
||||
|
||||
unsigned getShuffleMaskIdx(ASTContext &Ctx, unsigned N) {
|
||||
unsigned getShuffleMaskIdx(ASTContext &Ctx, unsigned N) const {
|
||||
assert((N < NumExprs - 2) && "Shuffle idx out of range!");
|
||||
return getExpr(N+2)->EvaluateKnownConstInt(Ctx).getZExtValue();
|
||||
}
|
||||
@ -3381,7 +3422,6 @@ class ChooseExpr : public Expr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ChooseExprClass;
|
||||
}
|
||||
static bool classof(const ChooseExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() {
|
||||
@ -3418,7 +3458,6 @@ class GNUNullExpr : public Expr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == GNUNullExprClass;
|
||||
}
|
||||
static bool classof(const GNUNullExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() { return child_range(); }
|
||||
@ -3464,7 +3503,6 @@ class VAArgExpr : public Expr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == VAArgExprClass;
|
||||
}
|
||||
static bool classof(const VAArgExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() { return child_range(&Val, &Val+1); }
|
||||
@ -3501,21 +3539,32 @@ class VAArgExpr : public Expr {
|
||||
/// initializer lists may still have fewer initializers than there are
|
||||
/// elements to initialize within the object.
|
||||
///
|
||||
/// After semantic analysis has completed, given an initializer list,
|
||||
/// method isSemanticForm() returns true if and only if this is the
|
||||
/// semantic form of the initializer list (note: the same AST node
|
||||
/// may at the same time be the syntactic form).
|
||||
/// Given the semantic form of the initializer list, one can retrieve
|
||||
/// the original syntactic form of that initializer list (if it
|
||||
/// exists) using getSyntacticForm(). Since many initializer lists
|
||||
/// have the same syntactic and semantic forms, getSyntacticForm() may
|
||||
/// return NULL, indicating that the current initializer list also
|
||||
/// serves as its syntactic form.
|
||||
/// the syntactic form of that initializer list (when different)
|
||||
/// using method getSyntacticForm(); the method returns null if applied
|
||||
/// to a initializer list which is already in syntactic form.
|
||||
/// Similarly, given the syntactic form (i.e., an initializer list such
|
||||
/// that isSemanticForm() returns false), one can retrieve the semantic
|
||||
/// form using method getSemanticForm().
|
||||
/// Since many initializer lists have the same syntactic and semantic forms,
|
||||
/// getSyntacticForm() may return NULL, indicating that the current
|
||||
/// semantic initializer list also serves as its syntactic form.
|
||||
class InitListExpr : public Expr {
|
||||
// FIXME: Eliminate this vector in favor of ASTContext allocation
|
||||
typedef ASTVector<Stmt *> InitExprsTy;
|
||||
InitExprsTy InitExprs;
|
||||
SourceLocation LBraceLoc, RBraceLoc;
|
||||
|
||||
/// Contains the initializer list that describes the syntactic form
|
||||
/// written in the source code.
|
||||
InitListExpr *SyntacticForm;
|
||||
/// The alternative form of the initializer list (if it exists).
|
||||
/// The int part of the pair stores whether this initalizer list is
|
||||
/// in semantic form. If not null, the pointer points to:
|
||||
/// - the syntactic form, if this is in semantic form;
|
||||
/// - the semantic form, if this is in syntactic form.
|
||||
llvm::PointerIntPair<InitListExpr *, 1, bool> AltForm;
|
||||
|
||||
/// \brief Either:
|
||||
/// If this initializer list initializes an array with more elements than
|
||||
@ -3528,8 +3577,7 @@ class InitListExpr : public Expr {
|
||||
|
||||
public:
|
||||
InitListExpr(ASTContext &C, SourceLocation lbraceloc,
|
||||
Expr **initexprs, unsigned numinits,
|
||||
SourceLocation rbraceloc);
|
||||
ArrayRef<Expr*> initExprs, SourceLocation rbraceloc);
|
||||
|
||||
/// \brief Build an empty initializer list.
|
||||
explicit InitListExpr(ASTContext &C, EmptyShell Empty)
|
||||
@ -3621,12 +3669,20 @@ class InitListExpr : public Expr {
|
||||
SourceLocation getRBraceLoc() const { return RBraceLoc; }
|
||||
void setRBraceLoc(SourceLocation Loc) { RBraceLoc = Loc; }
|
||||
|
||||
/// @brief Retrieve the initializer list that describes the
|
||||
/// syntactic form of the initializer.
|
||||
///
|
||||
///
|
||||
InitListExpr *getSyntacticForm() const { return SyntacticForm; }
|
||||
void setSyntacticForm(InitListExpr *Init) { SyntacticForm = Init; }
|
||||
bool isSemanticForm() const { return AltForm.getInt(); }
|
||||
InitListExpr *getSemanticForm() const {
|
||||
return isSemanticForm() ? 0 : AltForm.getPointer();
|
||||
}
|
||||
InitListExpr *getSyntacticForm() const {
|
||||
return isSemanticForm() ? AltForm.getPointer() : 0;
|
||||
}
|
||||
|
||||
void setSyntacticForm(InitListExpr *Init) {
|
||||
AltForm.setPointer(Init);
|
||||
AltForm.setInt(true);
|
||||
Init->AltForm.setPointer(this);
|
||||
Init->AltForm.setInt(false);
|
||||
}
|
||||
|
||||
bool hadArrayRangeDesignator() const {
|
||||
return InitListExprBits.HadArrayRangeDesignator != 0;
|
||||
@ -3647,7 +3703,6 @@ class InitListExpr : public Expr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == InitListExprClass;
|
||||
}
|
||||
static bool classof(const InitListExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() {
|
||||
@ -3723,8 +3778,7 @@ class DesignatedInitExpr : public Expr {
|
||||
DesignatedInitExpr(ASTContext &C, QualType Ty, unsigned NumDesignators,
|
||||
const Designator *Designators,
|
||||
SourceLocation EqualOrColonLoc, bool GNUSyntax,
|
||||
Expr **IndexExprs, unsigned NumIndexExprs,
|
||||
Expr *Init);
|
||||
ArrayRef<Expr*> IndexExprs, Expr *Init);
|
||||
|
||||
explicit DesignatedInitExpr(unsigned NumSubExprs)
|
||||
: Expr(DesignatedInitExprClass, EmptyShell()),
|
||||
@ -3885,7 +3939,7 @@ class DesignatedInitExpr : public Expr {
|
||||
|
||||
static DesignatedInitExpr *Create(ASTContext &C, Designator *Designators,
|
||||
unsigned NumDesignators,
|
||||
Expr **IndexExprs, unsigned NumIndexExprs,
|
||||
ArrayRef<Expr*> IndexExprs,
|
||||
SourceLocation EqualOrColonLoc,
|
||||
bool GNUSyntax, Expr *Init);
|
||||
|
||||
@ -3985,7 +4039,6 @@ class DesignatedInitExpr : public Expr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == DesignatedInitExprClass;
|
||||
}
|
||||
static bool classof(const DesignatedInitExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() {
|
||||
@ -4015,7 +4068,6 @@ class ImplicitValueInitExpr : public Expr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ImplicitValueInitExprClass;
|
||||
}
|
||||
static bool classof(const ImplicitValueInitExpr *) { return true; }
|
||||
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
return SourceRange();
|
||||
@ -4032,8 +4084,8 @@ class ParenListExpr : public Expr {
|
||||
SourceLocation LParenLoc, RParenLoc;
|
||||
|
||||
public:
|
||||
ParenListExpr(ASTContext& C, SourceLocation lparenloc, Expr **exprs,
|
||||
unsigned numexprs, SourceLocation rparenloc);
|
||||
ParenListExpr(ASTContext& C, SourceLocation lparenloc, ArrayRef<Expr*> exprs,
|
||||
SourceLocation rparenloc);
|
||||
|
||||
/// \brief Build an empty paren list.
|
||||
explicit ParenListExpr(EmptyShell Empty) : Expr(ParenListExprClass, Empty) { }
|
||||
@ -4061,7 +4113,6 @@ class ParenListExpr : public Expr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ParenListExprClass;
|
||||
}
|
||||
static bool classof(const ParenListExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() {
|
||||
@ -4109,18 +4160,18 @@ class GenericSelectionExpr : public Expr {
|
||||
public:
|
||||
GenericSelectionExpr(ASTContext &Context,
|
||||
SourceLocation GenericLoc, Expr *ControllingExpr,
|
||||
TypeSourceInfo **AssocTypes, Expr **AssocExprs,
|
||||
unsigned NumAssocs, SourceLocation DefaultLoc,
|
||||
SourceLocation RParenLoc,
|
||||
ArrayRef<TypeSourceInfo*> AssocTypes,
|
||||
ArrayRef<Expr*> AssocExprs,
|
||||
SourceLocation DefaultLoc, SourceLocation RParenLoc,
|
||||
bool ContainsUnexpandedParameterPack,
|
||||
unsigned ResultIndex);
|
||||
|
||||
/// This constructor is used in the result-dependent case.
|
||||
GenericSelectionExpr(ASTContext &Context,
|
||||
SourceLocation GenericLoc, Expr *ControllingExpr,
|
||||
TypeSourceInfo **AssocTypes, Expr **AssocExprs,
|
||||
unsigned NumAssocs, SourceLocation DefaultLoc,
|
||||
SourceLocation RParenLoc,
|
||||
ArrayRef<TypeSourceInfo*> AssocTypes,
|
||||
ArrayRef<Expr*> AssocExprs,
|
||||
SourceLocation DefaultLoc, SourceLocation RParenLoc,
|
||||
bool ContainsUnexpandedParameterPack);
|
||||
|
||||
explicit GenericSelectionExpr(EmptyShell Empty)
|
||||
@ -4176,7 +4227,6 @@ class GenericSelectionExpr : public Expr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == GenericSelectionExprClass;
|
||||
}
|
||||
static bool classof(const GenericSelectionExpr *) { return true; }
|
||||
|
||||
child_range children() {
|
||||
return child_range(SubExprs, SubExprs+END_EXPR+NumAssocs);
|
||||
@ -4247,7 +4297,6 @@ class ExtVectorElementExpr : public Expr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ExtVectorElementExprClass;
|
||||
}
|
||||
static bool classof(const ExtVectorElementExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() { return child_range(&Base, &Base+1); }
|
||||
@ -4289,7 +4338,6 @@ class BlockExpr : public Expr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == BlockExprClass;
|
||||
}
|
||||
static bool classof(const BlockExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() { return child_range(); }
|
||||
@ -4336,7 +4384,6 @@ class AsTypeExpr : public Expr { // Should this be an ExplicitCastExpr?
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == AsTypeExprClass;
|
||||
}
|
||||
static bool classof(const AsTypeExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() { return child_range(&SrcExpr, &SrcExpr+1); }
|
||||
@ -4473,7 +4520,6 @@ class PseudoObjectExpr : public Expr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == PseudoObjectExprClass;
|
||||
}
|
||||
static bool classof(const PseudoObjectExpr *) { return true; }
|
||||
};
|
||||
|
||||
/// AtomicExpr - Variadic atomic builtins: __atomic_exchange, __atomic_fetch_*,
|
||||
@ -4501,7 +4547,7 @@ class AtomicExpr : public Expr {
|
||||
friend class ASTStmtReader;
|
||||
|
||||
public:
|
||||
AtomicExpr(SourceLocation BLoc, Expr **args, unsigned nexpr, QualType t,
|
||||
AtomicExpr(SourceLocation BLoc, ArrayRef<Expr*> args, QualType t,
|
||||
AtomicOp op, SourceLocation RP);
|
||||
|
||||
/// \brief Determine the number of arguments the specified atomic builtin
|
||||
@ -4563,7 +4609,6 @@ class AtomicExpr : public Expr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == AtomicExprClass;
|
||||
}
|
||||
static bool classof(const AtomicExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() {
|
||||
|
@ -53,14 +53,19 @@ class CXXOperatorCallExpr : public CallExpr {
|
||||
OverloadedOperatorKind Operator;
|
||||
SourceRange Range;
|
||||
|
||||
// Record the FP_CONTRACT state that applies to this operator call. Only
|
||||
// meaningful for floating point types. For other types this value can be
|
||||
// set to false.
|
||||
unsigned FPContractable : 1;
|
||||
|
||||
SourceRange getSourceRangeImpl() const LLVM_READONLY;
|
||||
public:
|
||||
CXXOperatorCallExpr(ASTContext& C, OverloadedOperatorKind Op, Expr *fn,
|
||||
Expr **args, unsigned numargs, QualType t,
|
||||
ExprValueKind VK, SourceLocation operatorloc)
|
||||
: CallExpr(C, CXXOperatorCallExprClass, fn, 0, args, numargs, t, VK,
|
||||
ArrayRef<Expr*> args, QualType t, ExprValueKind VK,
|
||||
SourceLocation operatorloc, bool fpContractable)
|
||||
: CallExpr(C, CXXOperatorCallExprClass, fn, 0, args, t, VK,
|
||||
operatorloc),
|
||||
Operator(Op) {
|
||||
Operator(Op), FPContractable(fpContractable) {
|
||||
Range = getSourceRangeImpl();
|
||||
}
|
||||
explicit CXXOperatorCallExpr(ASTContext& C, EmptyShell Empty) :
|
||||
@ -83,7 +88,14 @@ class CXXOperatorCallExpr : public CallExpr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CXXOperatorCallExprClass;
|
||||
}
|
||||
static bool classof(const CXXOperatorCallExpr *) { return true; }
|
||||
|
||||
// Set the FP contractability status of this operator. Only meaningful for
|
||||
// operations on floating point types.
|
||||
void setFPContractable(bool FPC) { FPContractable = FPC; }
|
||||
|
||||
// Get the FP contractability status of this operator. Only meaningful for
|
||||
// operations on floating point types.
|
||||
bool isFPContractable() const { return FPContractable; }
|
||||
|
||||
friend class ASTStmtReader;
|
||||
friend class ASTStmtWriter;
|
||||
@ -99,9 +111,9 @@ class CXXOperatorCallExpr : public CallExpr {
|
||||
/// the object argument).
|
||||
class CXXMemberCallExpr : public CallExpr {
|
||||
public:
|
||||
CXXMemberCallExpr(ASTContext &C, Expr *fn, Expr **args, unsigned numargs,
|
||||
CXXMemberCallExpr(ASTContext &C, Expr *fn, ArrayRef<Expr*> args,
|
||||
QualType t, ExprValueKind VK, SourceLocation RP)
|
||||
: CallExpr(C, CXXMemberCallExprClass, fn, 0, args, numargs, t, VK, RP) {}
|
||||
: CallExpr(C, CXXMemberCallExprClass, fn, 0, args, t, VK, RP) {}
|
||||
|
||||
CXXMemberCallExpr(ASTContext &C, EmptyShell Empty)
|
||||
: CallExpr(C, CXXMemberCallExprClass, Empty) { }
|
||||
@ -124,7 +136,6 @@ class CXXMemberCallExpr : public CallExpr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CXXMemberCallExprClass;
|
||||
}
|
||||
static bool classof(const CXXMemberCallExpr *) { return true; }
|
||||
};
|
||||
|
||||
/// CUDAKernelCallExpr - Represents a call to a CUDA kernel function.
|
||||
@ -134,10 +145,9 @@ class CUDAKernelCallExpr : public CallExpr {
|
||||
|
||||
public:
|
||||
CUDAKernelCallExpr(ASTContext &C, Expr *fn, CallExpr *Config,
|
||||
Expr **args, unsigned numargs, QualType t,
|
||||
ExprValueKind VK, SourceLocation RP)
|
||||
: CallExpr(C, CUDAKernelCallExprClass, fn, END_PREARG, args, numargs, t, VK,
|
||||
RP) {
|
||||
ArrayRef<Expr*> args, QualType t, ExprValueKind VK,
|
||||
SourceLocation RP)
|
||||
: CallExpr(C, CUDAKernelCallExprClass, fn, END_PREARG, args, t, VK, RP) {
|
||||
setConfig(Config);
|
||||
}
|
||||
|
||||
@ -153,7 +163,6 @@ class CUDAKernelCallExpr : public CallExpr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CUDAKernelCallExprClass;
|
||||
}
|
||||
static bool classof(const CUDAKernelCallExpr *) { return true; }
|
||||
};
|
||||
|
||||
/// CXXNamedCastExpr - Abstract class common to all of the C++ "named"
|
||||
@ -205,7 +214,6 @@ class CXXNamedCastExpr : public ExplicitCastExpr {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
static bool classof(const CXXNamedCastExpr *) { return true; }
|
||||
};
|
||||
|
||||
/// CXXStaticCastExpr - A C++ @c static_cast expression
|
||||
@ -235,7 +243,6 @@ class CXXStaticCastExpr : public CXXNamedCastExpr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CXXStaticCastExprClass;
|
||||
}
|
||||
static bool classof(const CXXStaticCastExpr *) { return true; }
|
||||
};
|
||||
|
||||
/// CXXDynamicCastExpr - A C++ @c dynamic_cast expression
|
||||
@ -269,7 +276,6 @@ class CXXDynamicCastExpr : public CXXNamedCastExpr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CXXDynamicCastExprClass;
|
||||
}
|
||||
static bool classof(const CXXDynamicCastExpr *) { return true; }
|
||||
};
|
||||
|
||||
/// CXXReinterpretCastExpr - A C++ @c reinterpret_cast expression (C++
|
||||
@ -301,7 +307,6 @@ class CXXReinterpretCastExpr : public CXXNamedCastExpr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CXXReinterpretCastExprClass;
|
||||
}
|
||||
static bool classof(const CXXReinterpretCastExpr *) { return true; }
|
||||
};
|
||||
|
||||
/// CXXConstCastExpr - A C++ @c const_cast expression (C++ [expr.const.cast]),
|
||||
@ -329,7 +334,6 @@ class CXXConstCastExpr : public CXXNamedCastExpr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CXXConstCastExprClass;
|
||||
}
|
||||
static bool classof(const CXXConstCastExpr *) { return true; }
|
||||
};
|
||||
|
||||
/// UserDefinedLiteral - A call to a literal operator (C++11 [over.literal])
|
||||
@ -346,11 +350,11 @@ class UserDefinedLiteral : public CallExpr {
|
||||
SourceLocation UDSuffixLoc;
|
||||
|
||||
public:
|
||||
UserDefinedLiteral(ASTContext &C, Expr *Fn, Expr **Args, unsigned NumArgs,
|
||||
UserDefinedLiteral(ASTContext &C, Expr *Fn, ArrayRef<Expr*> Args,
|
||||
QualType T, ExprValueKind VK, SourceLocation LitEndLoc,
|
||||
SourceLocation SuffixLoc)
|
||||
: CallExpr(C, UserDefinedLiteralClass, Fn, 0, Args, NumArgs, T, VK,
|
||||
LitEndLoc), UDSuffixLoc(SuffixLoc) {}
|
||||
: CallExpr(C, UserDefinedLiteralClass, Fn, 0, Args, T, VK, LitEndLoc),
|
||||
UDSuffixLoc(SuffixLoc) {}
|
||||
explicit UserDefinedLiteral(ASTContext &C, EmptyShell Empty)
|
||||
: CallExpr(C, UserDefinedLiteralClass, Empty) {}
|
||||
|
||||
@ -398,7 +402,6 @@ class UserDefinedLiteral : public CallExpr {
|
||||
static bool classof(const Stmt *S) {
|
||||
return S->getStmtClass() == UserDefinedLiteralClass;
|
||||
}
|
||||
static bool classof(const UserDefinedLiteral *) { return true; }
|
||||
|
||||
friend class ASTStmtReader;
|
||||
friend class ASTStmtWriter;
|
||||
@ -429,7 +432,6 @@ class CXXBoolLiteralExpr : public Expr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CXXBoolLiteralExprClass;
|
||||
}
|
||||
static bool classof(const CXXBoolLiteralExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() { return child_range(); }
|
||||
@ -455,7 +457,6 @@ class CXXNullPtrLiteralExpr : public Expr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CXXNullPtrLiteralExprClass;
|
||||
}
|
||||
static bool classof(const CXXNullPtrLiteralExpr *) { return true; }
|
||||
|
||||
child_range children() { return child_range(); }
|
||||
};
|
||||
@ -536,7 +537,6 @@ class CXXTypeidExpr : public Expr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CXXTypeidExprClass;
|
||||
}
|
||||
static bool classof(const CXXTypeidExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() {
|
||||
@ -611,7 +611,9 @@ class CXXUuidofExpr : public Expr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CXXUuidofExprClass;
|
||||
}
|
||||
static bool classof(const CXXUuidofExpr *) { return true; }
|
||||
|
||||
/// Grabs __declspec(uuid()) off a type, or returns 0 if there is none.
|
||||
static UuidAttr *GetUuidAttrOfType(QualType QT);
|
||||
|
||||
// Iterators
|
||||
child_range children() {
|
||||
@ -659,7 +661,6 @@ class CXXThisExpr : public Expr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CXXThisExprClass;
|
||||
}
|
||||
static bool classof(const CXXThisExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() { return child_range(); }
|
||||
@ -710,7 +711,6 @@ class CXXThrowExpr : public Expr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CXXThrowExprClass;
|
||||
}
|
||||
static bool classof(const CXXThrowExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() {
|
||||
@ -798,7 +798,6 @@ class CXXDefaultArgExpr : public Expr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CXXDefaultArgExprClass;
|
||||
}
|
||||
static bool classof(const CXXDefaultArgExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() { return child_range(); }
|
||||
@ -875,7 +874,6 @@ class CXXBindTemporaryExpr : public Expr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CXXBindTemporaryExprClass;
|
||||
}
|
||||
static bool classof(const CXXBindTemporaryExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() { return child_range(&SubExpr, &SubExpr + 1); }
|
||||
@ -908,7 +906,7 @@ class CXXConstructExpr : public Expr {
|
||||
CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T,
|
||||
SourceLocation Loc,
|
||||
CXXConstructorDecl *d, bool elidable,
|
||||
Expr **args, unsigned numargs,
|
||||
ArrayRef<Expr *> Args,
|
||||
bool HadMultipleCandidates,
|
||||
bool ListInitialization,
|
||||
bool ZeroInitialization,
|
||||
@ -934,7 +932,7 @@ class CXXConstructExpr : public Expr {
|
||||
static CXXConstructExpr *Create(ASTContext &C, QualType T,
|
||||
SourceLocation Loc,
|
||||
CXXConstructorDecl *D, bool Elidable,
|
||||
Expr **Args, unsigned NumArgs,
|
||||
ArrayRef<Expr *> Args,
|
||||
bool HadMultipleCandidates,
|
||||
bool ListInitialization,
|
||||
bool ZeroInitialization,
|
||||
@ -1011,7 +1009,6 @@ class CXXConstructExpr : public Expr {
|
||||
return T->getStmtClass() == CXXConstructExprClass ||
|
||||
T->getStmtClass() == CXXTemporaryObjectExprClass;
|
||||
}
|
||||
static bool classof(const CXXConstructExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() {
|
||||
@ -1066,7 +1063,6 @@ class CXXFunctionalCastExpr : public ExplicitCastExpr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CXXFunctionalCastExprClass;
|
||||
}
|
||||
static bool classof(const CXXFunctionalCastExpr *) { return true; }
|
||||
};
|
||||
|
||||
/// @brief Represents a C++ functional cast expression that builds a
|
||||
@ -1090,7 +1086,7 @@ class CXXTemporaryObjectExpr : public CXXConstructExpr {
|
||||
public:
|
||||
CXXTemporaryObjectExpr(ASTContext &C, CXXConstructorDecl *Cons,
|
||||
TypeSourceInfo *Type,
|
||||
Expr **Args,unsigned NumArgs,
|
||||
ArrayRef<Expr *> Args,
|
||||
SourceRange parenRange,
|
||||
bool HadMultipleCandidates,
|
||||
bool ZeroInitialization = false);
|
||||
@ -1104,7 +1100,6 @@ class CXXTemporaryObjectExpr : public CXXConstructExpr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CXXTemporaryObjectExprClass;
|
||||
}
|
||||
static bool classof(const CXXTemporaryObjectExpr *) { return true; }
|
||||
|
||||
friend class ASTStmtReader;
|
||||
};
|
||||
@ -1281,8 +1276,11 @@ class LambdaExpr : public Expr {
|
||||
|
||||
/// \brief Retrieve the complete set of array-index variables.
|
||||
VarDecl **getArrayIndexVars() const {
|
||||
unsigned ArrayIndexSize =
|
||||
llvm::RoundUpToAlignment(sizeof(unsigned) * (NumCaptures + 1),
|
||||
llvm::alignOf<VarDecl*>());
|
||||
return reinterpret_cast<VarDecl **>(
|
||||
getArrayIndexStarts() + NumCaptures + 1);
|
||||
reinterpret_cast<char*>(getArrayIndexStarts()) + ArrayIndexSize);
|
||||
}
|
||||
|
||||
public:
|
||||
@ -1394,7 +1392,6 @@ class LambdaExpr : public Expr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == LambdaExprClass;
|
||||
}
|
||||
static bool classof(const LambdaExpr *) { return true; }
|
||||
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
return SourceRange(IntroducerRange.getBegin(), ClosingBrace);
|
||||
@ -1442,7 +1439,6 @@ class CXXScalarValueInitExpr : public Expr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CXXScalarValueInitExprClass;
|
||||
}
|
||||
static bool classof(const CXXScalarValueInitExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() { return child_range(); }
|
||||
@ -1467,8 +1463,8 @@ class CXXNewExpr : public Expr {
|
||||
/// the source range covering the parenthesized type-id.
|
||||
SourceRange TypeIdParens;
|
||||
|
||||
/// \brief Location of the first token.
|
||||
SourceLocation StartLoc;
|
||||
/// \brief Range of the entire new expression.
|
||||
SourceRange Range;
|
||||
|
||||
/// \brief Source-range of a paren-delimited initializer.
|
||||
SourceRange DirectInitRange;
|
||||
@ -1498,11 +1494,11 @@ class CXXNewExpr : public Expr {
|
||||
|
||||
CXXNewExpr(ASTContext &C, bool globalNew, FunctionDecl *operatorNew,
|
||||
FunctionDecl *operatorDelete, bool usualArrayDeleteWantsSize,
|
||||
Expr **placementArgs, unsigned numPlaceArgs,
|
||||
ArrayRef<Expr*> placementArgs,
|
||||
SourceRange typeIdParens, Expr *arraySize,
|
||||
InitializationStyle initializationStyle, Expr *initializer,
|
||||
QualType ty, TypeSourceInfo *AllocatedTypeInfo,
|
||||
SourceLocation startLoc, SourceRange directInitRange);
|
||||
SourceRange Range, SourceRange directInitRange);
|
||||
explicit CXXNewExpr(EmptyShell Shell)
|
||||
: Expr(CXXNewExprClass, Shell), SubExprs(0) { }
|
||||
|
||||
@ -1580,7 +1576,7 @@ class CXXNewExpr : public Expr {
|
||||
}
|
||||
|
||||
/// \brief Returns the CXXConstructExpr from this new-expression, or NULL.
|
||||
const CXXConstructExpr* getConstructExpr() {
|
||||
const CXXConstructExpr* getConstructExpr() const {
|
||||
return dyn_cast_or_null<CXXConstructExpr>(getInitializer());
|
||||
}
|
||||
|
||||
@ -1617,19 +1613,18 @@ class CXXNewExpr : public Expr {
|
||||
return SubExprs + Array + hasInitializer() + getNumPlacementArgs();
|
||||
}
|
||||
|
||||
SourceLocation getStartLoc() const { return StartLoc; }
|
||||
SourceLocation getEndLoc() const;
|
||||
SourceLocation getStartLoc() const { return Range.getBegin(); }
|
||||
SourceLocation getEndLoc() const { return Range.getEnd(); }
|
||||
|
||||
SourceRange getDirectInitRange() const { return DirectInitRange; }
|
||||
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
return SourceRange(getStartLoc(), getEndLoc());
|
||||
return Range;
|
||||
}
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CXXNewExprClass;
|
||||
}
|
||||
static bool classof(const CXXNewExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() {
|
||||
@ -1700,7 +1695,6 @@ class CXXDeleteExpr : public Expr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CXXDeleteExprClass;
|
||||
}
|
||||
static bool classof(const CXXDeleteExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() { return child_range(&Argument, &Argument+1); }
|
||||
@ -1889,7 +1883,6 @@ class CXXPseudoDestructorExpr : public Expr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CXXPseudoDestructorExprClass;
|
||||
}
|
||||
static bool classof(const CXXPseudoDestructorExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() { return child_range(&Base, &Base + 1); }
|
||||
@ -1945,7 +1938,6 @@ class UnaryTypeTraitExpr : public Expr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == UnaryTypeTraitExprClass;
|
||||
}
|
||||
static bool classof(const UnaryTypeTraitExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() { return child_range(); }
|
||||
@ -2017,7 +2009,6 @@ class BinaryTypeTraitExpr : public Expr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == BinaryTypeTraitExprClass;
|
||||
}
|
||||
static bool classof(const BinaryTypeTraitExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() { return child_range(); }
|
||||
@ -2111,7 +2102,6 @@ class TypeTraitExpr : public Expr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == TypeTraitExprClass;
|
||||
}
|
||||
static bool classof(const TypeTraitExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() { return child_range(); }
|
||||
@ -2186,7 +2176,6 @@ class ArrayTypeTraitExpr : public Expr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ArrayTypeTraitExprClass;
|
||||
}
|
||||
static bool classof(const ArrayTypeTraitExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() { return child_range(); }
|
||||
@ -2245,7 +2234,6 @@ class ExpressionTraitExpr : public Expr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ExpressionTraitExprClass;
|
||||
}
|
||||
static bool classof(const ExpressionTraitExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() { return child_range(); }
|
||||
@ -2432,7 +2420,6 @@ class OverloadExpr : public Expr {
|
||||
return T->getStmtClass() == UnresolvedLookupExprClass ||
|
||||
T->getStmtClass() == UnresolvedMemberExprClass;
|
||||
}
|
||||
static bool classof(const OverloadExpr *) { return true; }
|
||||
|
||||
friend class ASTStmtReader;
|
||||
friend class ASTStmtWriter;
|
||||
@ -2454,10 +2441,6 @@ class UnresolvedLookupExpr : public OverloadExpr {
|
||||
/// call.
|
||||
bool RequiresADL;
|
||||
|
||||
/// True if namespace ::std should be considered an associated namespace
|
||||
/// for the purposes of argument-dependent lookup. See C++0x [stmt.ranged]p1.
|
||||
bool StdIsAssociatedNamespace;
|
||||
|
||||
/// True if these lookup results are overloaded. This is pretty
|
||||
/// trivially rederivable if we urgently need to kill this field.
|
||||
bool Overloaded;
|
||||
@ -2476,19 +2459,16 @@ class UnresolvedLookupExpr : public OverloadExpr {
|
||||
const DeclarationNameInfo &NameInfo,
|
||||
bool RequiresADL, bool Overloaded,
|
||||
const TemplateArgumentListInfo *TemplateArgs,
|
||||
UnresolvedSetIterator Begin, UnresolvedSetIterator End,
|
||||
bool StdIsAssociatedNamespace)
|
||||
UnresolvedSetIterator Begin, UnresolvedSetIterator End)
|
||||
: OverloadExpr(UnresolvedLookupExprClass, C, QualifierLoc, TemplateKWLoc,
|
||||
NameInfo, TemplateArgs, Begin, End, false, false, false),
|
||||
RequiresADL(RequiresADL),
|
||||
StdIsAssociatedNamespace(StdIsAssociatedNamespace),
|
||||
Overloaded(Overloaded), NamingClass(NamingClass)
|
||||
{}
|
||||
|
||||
UnresolvedLookupExpr(EmptyShell Empty)
|
||||
: OverloadExpr(UnresolvedLookupExprClass, Empty),
|
||||
RequiresADL(false), StdIsAssociatedNamespace(false), Overloaded(false),
|
||||
NamingClass(0)
|
||||
RequiresADL(false), Overloaded(false), NamingClass(0)
|
||||
{}
|
||||
|
||||
friend class ASTStmtReader;
|
||||
@ -2500,14 +2480,10 @@ class UnresolvedLookupExpr : public OverloadExpr {
|
||||
const DeclarationNameInfo &NameInfo,
|
||||
bool ADL, bool Overloaded,
|
||||
UnresolvedSetIterator Begin,
|
||||
UnresolvedSetIterator End,
|
||||
bool StdIsAssociatedNamespace = false) {
|
||||
assert((ADL || !StdIsAssociatedNamespace) &&
|
||||
"std considered associated namespace when not performing ADL");
|
||||
UnresolvedSetIterator End) {
|
||||
return new(C) UnresolvedLookupExpr(C, NamingClass, QualifierLoc,
|
||||
SourceLocation(), NameInfo,
|
||||
ADL, Overloaded, 0, Begin, End,
|
||||
StdIsAssociatedNamespace);
|
||||
ADL, Overloaded, 0, Begin, End);
|
||||
}
|
||||
|
||||
static UnresolvedLookupExpr *Create(ASTContext &C,
|
||||
@ -2528,10 +2504,6 @@ class UnresolvedLookupExpr : public OverloadExpr {
|
||||
/// argument-dependent lookup.
|
||||
bool requiresADL() const { return RequiresADL; }
|
||||
|
||||
/// True if namespace \::std should be artificially added to the set of
|
||||
/// associated namespaces for argument-dependent lookup purposes.
|
||||
bool isStdAssociatedNamespace() const { return StdIsAssociatedNamespace; }
|
||||
|
||||
/// True if this lookup is overloaded.
|
||||
bool isOverloaded() const { return Overloaded; }
|
||||
|
||||
@ -2554,7 +2526,6 @@ class UnresolvedLookupExpr : public OverloadExpr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == UnresolvedLookupExprClass;
|
||||
}
|
||||
static bool classof(const UnresolvedLookupExpr *) { return true; }
|
||||
};
|
||||
|
||||
/// \brief A qualified reference to a name whose declaration cannot
|
||||
@ -2705,7 +2676,6 @@ class DependentScopeDeclRefExpr : public Expr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == DependentScopeDeclRefExprClass;
|
||||
}
|
||||
static bool classof(const DependentScopeDeclRefExpr *) { return true; }
|
||||
|
||||
child_range children() { return child_range(); }
|
||||
|
||||
@ -2778,7 +2748,6 @@ class ExprWithCleanups : public Expr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ExprWithCleanupsClass;
|
||||
}
|
||||
static bool classof(const ExprWithCleanups *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() { return child_range(&SubExpr, &SubExpr + 1); }
|
||||
@ -2820,8 +2789,7 @@ class CXXUnresolvedConstructExpr : public Expr {
|
||||
|
||||
CXXUnresolvedConstructExpr(TypeSourceInfo *Type,
|
||||
SourceLocation LParenLoc,
|
||||
Expr **Args,
|
||||
unsigned NumArgs,
|
||||
ArrayRef<Expr*> Args,
|
||||
SourceLocation RParenLoc);
|
||||
|
||||
CXXUnresolvedConstructExpr(EmptyShell Empty, unsigned NumArgs)
|
||||
@ -2833,8 +2801,7 @@ class CXXUnresolvedConstructExpr : public Expr {
|
||||
static CXXUnresolvedConstructExpr *Create(ASTContext &C,
|
||||
TypeSourceInfo *Type,
|
||||
SourceLocation LParenLoc,
|
||||
Expr **Args,
|
||||
unsigned NumArgs,
|
||||
ArrayRef<Expr*> Args,
|
||||
SourceLocation RParenLoc);
|
||||
|
||||
static CXXUnresolvedConstructExpr *CreateEmpty(ASTContext &C,
|
||||
@ -2893,7 +2860,6 @@ class CXXUnresolvedConstructExpr : public Expr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CXXUnresolvedConstructExprClass;
|
||||
}
|
||||
static bool classof(const CXXUnresolvedConstructExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() {
|
||||
@ -3142,7 +3108,6 @@ class CXXDependentScopeMemberExpr : public Expr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CXXDependentScopeMemberExprClass;
|
||||
}
|
||||
static bool classof(const CXXDependentScopeMemberExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() {
|
||||
@ -3276,7 +3241,6 @@ class UnresolvedMemberExpr : public OverloadExpr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == UnresolvedMemberExprClass;
|
||||
}
|
||||
static bool classof(const UnresolvedMemberExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() {
|
||||
@ -3320,7 +3284,6 @@ class CXXNoexceptExpr : public Expr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CXXNoexceptExprClass;
|
||||
}
|
||||
static bool classof(const CXXNoexceptExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() { return child_range(&Operand, &Operand + 1); }
|
||||
@ -3397,7 +3360,6 @@ class PackExpansionExpr : public Expr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == PackExpansionExprClass;
|
||||
}
|
||||
static bool classof(const PackExpansionExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() {
|
||||
@ -3503,7 +3465,6 @@ class SizeOfPackExpr : public Expr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == SizeOfPackExprClass;
|
||||
}
|
||||
static bool classof(const SizeOfPackExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() { return child_range(); }
|
||||
@ -3548,9 +3509,6 @@ class SubstNonTypeTemplateParmExpr : public Expr {
|
||||
static bool classof(const Stmt *s) {
|
||||
return s->getStmtClass() == SubstNonTypeTemplateParmExprClass;
|
||||
}
|
||||
static bool classof(const SubstNonTypeTemplateParmExpr *) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Iterators
|
||||
child_range children() { return child_range(&Replacement, &Replacement+1); }
|
||||
@ -3561,7 +3519,7 @@ class SubstNonTypeTemplateParmExpr : public Expr {
|
||||
///
|
||||
/// When a pack expansion in the source code contains multiple parameter packs
|
||||
/// and those parameter packs correspond to different levels of template
|
||||
/// parameter lists, this node node is used to represent a non-type template
|
||||
/// parameter lists, this node is used to represent a non-type template
|
||||
/// parameter pack from an outer level, which has already had its argument pack
|
||||
/// substituted but that still lives within a pack expansion that itself
|
||||
/// could not be instantiated. When actually performing a substitution into
|
||||
@ -3608,14 +3566,77 @@ class SubstNonTypeTemplateParmPackExpr : public Expr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == SubstNonTypeTemplateParmPackExprClass;
|
||||
}
|
||||
static bool classof(const SubstNonTypeTemplateParmPackExpr *) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Iterators
|
||||
child_range children() { return child_range(); }
|
||||
};
|
||||
|
||||
/// \brief Represents a reference to a function parameter pack that has been
|
||||
/// substituted but not yet expanded.
|
||||
///
|
||||
/// When a pack expansion contains multiple parameter packs at different levels,
|
||||
/// this node is used to represent a function parameter pack at an outer level
|
||||
/// which we have already substituted to refer to expanded parameters, but where
|
||||
/// the containing pack expansion cannot yet be expanded.
|
||||
///
|
||||
/// \code
|
||||
/// template<typename...Ts> struct S {
|
||||
/// template<typename...Us> auto f(Ts ...ts) -> decltype(g(Us(ts)...));
|
||||
/// };
|
||||
/// template struct S<int, int>;
|
||||
/// \endcode
|
||||
class FunctionParmPackExpr : public Expr {
|
||||
/// \brief The function parameter pack which was referenced.
|
||||
ParmVarDecl *ParamPack;
|
||||
|
||||
/// \brief The location of the function parameter pack reference.
|
||||
SourceLocation NameLoc;
|
||||
|
||||
/// \brief The number of expansions of this pack.
|
||||
unsigned NumParameters;
|
||||
|
||||
FunctionParmPackExpr(QualType T, ParmVarDecl *ParamPack,
|
||||
SourceLocation NameLoc, unsigned NumParams,
|
||||
Decl * const *Params);
|
||||
|
||||
friend class ASTReader;
|
||||
friend class ASTStmtReader;
|
||||
|
||||
public:
|
||||
static FunctionParmPackExpr *Create(ASTContext &Context, QualType T,
|
||||
ParmVarDecl *ParamPack,
|
||||
SourceLocation NameLoc,
|
||||
llvm::ArrayRef<Decl*> Params);
|
||||
static FunctionParmPackExpr *CreateEmpty(ASTContext &Context,
|
||||
unsigned NumParams);
|
||||
|
||||
/// \brief Get the parameter pack which this expression refers to.
|
||||
ParmVarDecl *getParameterPack() const { return ParamPack; }
|
||||
|
||||
/// \brief Get the location of the parameter pack.
|
||||
SourceLocation getParameterPackLocation() const { return NameLoc; }
|
||||
|
||||
/// \brief Iterators over the parameters which the parameter pack expanded
|
||||
/// into.
|
||||
typedef ParmVarDecl * const *iterator;
|
||||
iterator begin() const { return reinterpret_cast<iterator>(this+1); }
|
||||
iterator end() const { return begin() + NumParameters; }
|
||||
|
||||
/// \brief Get the number of parameters in this parameter pack.
|
||||
unsigned getNumExpansions() const { return NumParameters; }
|
||||
|
||||
/// \brief Get an expansion of the parameter pack by index.
|
||||
ParmVarDecl *getExpansion(unsigned I) const { return begin()[I]; }
|
||||
|
||||
SourceRange getSourceRange() const LLVM_READONLY { return NameLoc; }
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == FunctionParmPackExprClass;
|
||||
}
|
||||
|
||||
child_range children() { return child_range(); }
|
||||
};
|
||||
|
||||
/// \brief Represents a prvalue temporary that written into memory so that
|
||||
/// a reference can bind to it.
|
||||
///
|
||||
@ -3670,9 +3691,6 @@ class MaterializeTemporaryExpr : public Expr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == MaterializeTemporaryExprClass;
|
||||
}
|
||||
static bool classof(const MaterializeTemporaryExpr *) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Iterators
|
||||
child_range children() { return child_range(&Temporary, &Temporary + 1); }
|
||||
|
@ -51,7 +51,6 @@ class ObjCStringLiteral : public Expr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCStringLiteralClass;
|
||||
}
|
||||
static bool classof(const ObjCStringLiteral *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() { return child_range(&String, &String+1); }
|
||||
@ -81,7 +80,6 @@ class ObjCBoolLiteralExpr : public Expr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCBoolLiteralExprClass;
|
||||
}
|
||||
static bool classof(const ObjCBoolLiteralExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() { return child_range(); }
|
||||
@ -121,7 +119,6 @@ class ObjCBoxedExpr : public Expr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCBoxedExprClass;
|
||||
}
|
||||
static bool classof(const ObjCBoxedExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() { return child_range(&SubExpr, &SubExpr+1); }
|
||||
@ -156,7 +153,6 @@ class ObjCArrayLiteral : public Expr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCArrayLiteralClass;
|
||||
}
|
||||
static bool classof(const ObjCArrayLiteral *) { return true; }
|
||||
|
||||
/// \brief Retrieve elements of array of literals.
|
||||
Expr **getElements() { return reinterpret_cast<Expr **>(this + 1); }
|
||||
@ -319,7 +315,6 @@ class ObjCDictionaryLiteral : public Expr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCDictionaryLiteralClass;
|
||||
}
|
||||
static bool classof(const ObjCDictionaryLiteral *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() {
|
||||
@ -372,7 +367,6 @@ class ObjCEncodeExpr : public Expr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCEncodeExprClass;
|
||||
}
|
||||
static bool classof(const ObjCEncodeExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() { return child_range(); }
|
||||
@ -409,7 +403,6 @@ class ObjCSelectorExpr : public Expr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCSelectorExprClass;
|
||||
}
|
||||
static bool classof(const ObjCSelectorExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() { return child_range(); }
|
||||
@ -447,7 +440,6 @@ class ObjCProtocolExpr : public Expr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCProtocolExprClass;
|
||||
}
|
||||
static bool classof(const ObjCProtocolExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() { return child_range(); }
|
||||
@ -501,7 +493,6 @@ class ObjCIvarRefExpr : public Expr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCIvarRefExprClass;
|
||||
}
|
||||
static bool classof(const ObjCIvarRefExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() { return child_range(&Base, &Base+1); }
|
||||
@ -715,7 +706,6 @@ class ObjCPropertyRefExpr : public Expr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCPropertyRefExprClass;
|
||||
}
|
||||
static bool classof(const ObjCPropertyRefExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() {
|
||||
@ -813,7 +803,6 @@ class ObjCSubscriptRefExpr : public Expr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCSubscriptRefExprClass;
|
||||
}
|
||||
static bool classof(const ObjCSubscriptRefExpr *) { return true; }
|
||||
|
||||
Expr *getBaseExpr() const { return cast<Expr>(SubExprs[BASE]); }
|
||||
void setBaseExpr(Stmt *S) { SubExprs[BASE] = S; }
|
||||
@ -1156,10 +1145,8 @@ class ObjCMessageExpr : public Expr {
|
||||
return getReceiverKind() == Class || getReceiverKind() == SuperClass;
|
||||
}
|
||||
|
||||
/// \brief Returns the receiver of an instance message.
|
||||
///
|
||||
/// \brief Returns the object expression for an instance message, or
|
||||
/// NULL for a message that is not an instance message.
|
||||
/// \brief Returns the object expression (receiver) for an instance message,
|
||||
/// or null for a message that is not an instance message.
|
||||
Expr *getInstanceReceiver() {
|
||||
if (getReceiverKind() == Instance)
|
||||
return static_cast<Expr *>(getReceiverPointer());
|
||||
@ -1208,6 +1195,17 @@ class ObjCMessageExpr : public Expr {
|
||||
return SourceLocation();
|
||||
}
|
||||
|
||||
/// \brief Retrieve the receiver type to which this message is being directed.
|
||||
///
|
||||
/// This routine cross-cuts all of the different kinds of message
|
||||
/// sends to determine what the underlying (statically known) type
|
||||
/// of the receiver will be; use \c getReceiverKind() to determine
|
||||
/// whether the message is a class or an instance method, whether it
|
||||
/// is a send to super or not, etc.
|
||||
///
|
||||
/// \returns The type of the receiver.
|
||||
QualType getReceiverType() const;
|
||||
|
||||
/// \brief Retrieve the Objective-C interface to which this message
|
||||
/// is being directed, if known.
|
||||
///
|
||||
@ -1344,7 +1342,6 @@ class ObjCMessageExpr : public Expr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCMessageExprClass;
|
||||
}
|
||||
static bool classof(const ObjCMessageExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children();
|
||||
@ -1409,7 +1406,6 @@ class ObjCIsaExpr : public Expr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCIsaExprClass;
|
||||
}
|
||||
static bool classof(const ObjCIsaExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() { return child_range(&Base, &Base+1); }
|
||||
@ -1483,7 +1479,6 @@ class ObjCIndirectCopyRestoreExpr : public Expr {
|
||||
static bool classof(const Stmt *s) {
|
||||
return s->getStmtClass() == ObjCIndirectCopyRestoreExprClass;
|
||||
}
|
||||
static bool classof(const ObjCIndirectCopyRestoreExpr *) { return true; }
|
||||
};
|
||||
|
||||
/// \brief An Objective-C "bridged" cast expression, which casts between
|
||||
@ -1532,8 +1527,6 @@ class ObjCBridgedCastExpr : public ExplicitCastExpr {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCBridgedCastExprClass;
|
||||
}
|
||||
static bool classof(const ObjCBridgedCastExpr *) { return true; }
|
||||
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
@ -162,7 +162,7 @@ class ExternalASTSource {
|
||||
}
|
||||
|
||||
/// \brief Get the decls that are contained in a file in the Offset/Length
|
||||
/// range. \arg Length can be 0 to indicate a point at \arg Offset instead of
|
||||
/// range. \p Length can be 0 to indicate a point at \p Offset instead of
|
||||
/// a range.
|
||||
virtual void FindFileRegionDecls(FileID File, unsigned Offset,unsigned Length,
|
||||
SmallVectorImpl<Decl *> &Decls) {}
|
||||
|
@ -1,6 +1,8 @@
|
||||
CLANG_LEVEL := ../../..
|
||||
TD_SRC_DIR = $(PROJ_SRC_DIR)/../Basic
|
||||
BUILT_SOURCES = Attrs.inc AttrImpl.inc StmtNodes.inc DeclNodes.inc CommentNodes.inc
|
||||
BUILT_SOURCES = Attrs.inc AttrImpl.inc StmtNodes.inc DeclNodes.inc \
|
||||
CommentNodes.inc CommentHTMLTags.inc \
|
||||
CommentHTMLTagsProperties.inc CommentCommandInfo.inc
|
||||
|
||||
TABLEGEN_INC_FILES_COMMON = 1
|
||||
|
||||
@ -33,3 +35,18 @@ $(ObjDir)/CommentNodes.inc.tmp : $(TD_SRC_DIR)/CommentNodes.td $(CLANG_TBLGEN) \
|
||||
$(Echo) "Building Clang comment node tables with tblgen"
|
||||
$(Verb) $(ClangTableGen) -gen-clang-comment-nodes -o $(call SYSPATH, $@) $<
|
||||
|
||||
$(ObjDir)/CommentHTMLTags.inc.tmp : $(PROJ_SRC_DIR)/CommentHTMLTags.td $(CLANG_TBLGEN) \
|
||||
$(ObjDir)/.dir
|
||||
$(Echo) "Building Clang comment HTML tag matchers with tblgen"
|
||||
$(Verb) $(ClangTableGen) -gen-clang-comment-html-tags -o $(call SYSPATH, $@) $<
|
||||
|
||||
$(ObjDir)/CommentHTMLTagsProperties.inc.tmp : $(PROJ_SRC_DIR)/CommentHTMLTags.td \
|
||||
$(CLANG_TBLGEN) $(ObjDir)/.dir
|
||||
$(Echo) "Building Clang comment HTML tag properties with tblgen"
|
||||
$(Verb) $(ClangTableGen) -gen-clang-comment-html-tags-properties -o $(call SYSPATH, $@) $<
|
||||
|
||||
$(ObjDir)/CommentCommandInfo.inc.tmp : $(PROJ_SRC_DIR)/CommentCommands.td \
|
||||
$(CLANG_TBLGEN) $(ObjDir)/.dir
|
||||
$(Echo) "Building Clang comment command info with tblgen"
|
||||
$(Verb) $(ClangTableGen) -gen-clang-comment-command-info -o $(call SYSPATH, $@) $<
|
||||
|
||||
|
@ -83,7 +83,7 @@ class NSAPI {
|
||||
/// \brief The Objective-C NSArray selectors.
|
||||
Selector getNSArraySelector(NSArrayMethodKind MK) const;
|
||||
|
||||
/// \brief Return NSArrayMethodKind if \arg Sel is such a selector.
|
||||
/// \brief Return NSArrayMethodKind if \p Sel is such a selector.
|
||||
llvm::Optional<NSArrayMethodKind> getNSArrayMethodKind(Selector Sel);
|
||||
|
||||
/// \brief Enumerates the NSDictionary methods used to generate literals.
|
||||
@ -104,7 +104,7 @@ class NSAPI {
|
||||
/// \brief The Objective-C NSDictionary selectors.
|
||||
Selector getNSDictionarySelector(NSDictionaryMethodKind MK) const;
|
||||
|
||||
/// \brief Return NSDictionaryMethodKind if \arg Sel is such a selector.
|
||||
/// \brief Return NSDictionaryMethodKind if \p Sel is such a selector.
|
||||
llvm::Optional<NSDictionaryMethodKind>
|
||||
getNSDictionaryMethodKind(Selector Sel);
|
||||
|
||||
@ -169,7 +169,7 @@ class NSAPI {
|
||||
Sel == getNSNumberLiteralSelector(MK, true);
|
||||
}
|
||||
|
||||
/// \brief Return NSNumberLiteralMethodKind if \arg Sel is such a selector.
|
||||
/// \brief Return NSNumberLiteralMethodKind if \p Sel is such a selector.
|
||||
llvm::Optional<NSNumberLiteralMethodKind>
|
||||
getNSNumberLiteralMethodKind(Selector Sel) const;
|
||||
|
||||
|
@ -97,8 +97,7 @@ class NestedNameSpecifier : public llvm::FoldingSetNode {
|
||||
Specifier(Other.Specifier) {
|
||||
}
|
||||
|
||||
NestedNameSpecifier &operator=(const NestedNameSpecifier &); // do not
|
||||
// implement
|
||||
void operator=(const NestedNameSpecifier &) LLVM_DELETED_FUNCTION;
|
||||
|
||||
/// \brief Either find or insert the given nested name specifier
|
||||
/// mockup in the given context.
|
||||
|
@ -288,7 +288,11 @@ enum CastKind {
|
||||
///
|
||||
/// This particular cast kind is used for the conversion from a C++11
|
||||
/// lambda expression to a block pointer.
|
||||
CK_CopyAndAutoreleaseBlockObject
|
||||
CK_CopyAndAutoreleaseBlockObject,
|
||||
|
||||
// Convert a builtin function to a function pointer; only allowed in the
|
||||
// callee of a call expression.
|
||||
CK_BuiltinFnToFnPtr
|
||||
};
|
||||
|
||||
static const CastKind CK_Invalid = static_cast<CastKind>(-1);
|
||||
|
@ -39,6 +39,7 @@ struct PrintingPolicy {
|
||||
SuppressUnwrittenScope(false), SuppressInitializers(false),
|
||||
ConstantArraySizeAsWritten(false), AnonymousTagLocations(true),
|
||||
SuppressStrongLifetime(false), Bool(LO.Bool),
|
||||
TerseOutput(false), SuppressAttributes(false),
|
||||
DumpSourceManager(0) { }
|
||||
|
||||
/// \brief What language we're printing.
|
||||
@ -134,6 +135,17 @@ struct PrintingPolicy {
|
||||
/// doesn't actually have 'bool' (because, e.g., it is defined as a macro).
|
||||
unsigned Bool : 1;
|
||||
|
||||
/// \brief Provide a 'terse' output.
|
||||
///
|
||||
/// For example, in this mode we don't print function bodies, class members,
|
||||
/// declarations inside namespaces etc. Effectively, this should print
|
||||
/// only the requested declaration.
|
||||
unsigned TerseOutput : 1;
|
||||
|
||||
/// \brief When true, do not print attributes attached to the declaration.
|
||||
///
|
||||
unsigned SuppressAttributes : 1;
|
||||
|
||||
/// \brief If we are "dumping" rather than "pretty-printing", this points to
|
||||
/// a SourceManager which will be used to dump SourceLocations. Dumping
|
||||
/// involves printing the internal details of the AST and pretty-printing
|
||||
|
@ -18,6 +18,7 @@ namespace clang {
|
||||
class ASTContext;
|
||||
class ASTReader;
|
||||
class Decl;
|
||||
class Preprocessor;
|
||||
|
||||
namespace comments {
|
||||
class FullComment;
|
||||
@ -114,7 +115,8 @@ class RawComment {
|
||||
}
|
||||
|
||||
/// Parse the comment, assuming it is attached to decl \c D.
|
||||
comments::FullComment *parse(const ASTContext &Context, const Decl *D) const;
|
||||
comments::FullComment *parse(const ASTContext &Context,
|
||||
const Preprocessor *PP, const Decl *D) const;
|
||||
|
||||
private:
|
||||
SourceRange Range;
|
||||
@ -188,7 +190,7 @@ class RawCommentList {
|
||||
private:
|
||||
SourceManager &SourceMgr;
|
||||
std::vector<RawComment *> Comments;
|
||||
RawComment LastComment;
|
||||
SourceLocation PrevCommentEndLoc;
|
||||
bool OnlyWhitespaceSeen;
|
||||
|
||||
void addCommentsToFront(const std::vector<RawComment *> &C) {
|
||||
|
@ -136,8 +136,8 @@ class ASTRecordLayout {
|
||||
|
||||
void Destroy(ASTContext &Ctx);
|
||||
|
||||
ASTRecordLayout(const ASTRecordLayout&); // DO NOT IMPLEMENT
|
||||
void operator=(const ASTRecordLayout&); // DO NOT IMPLEMENT
|
||||
ASTRecordLayout(const ASTRecordLayout &) LLVM_DELETED_FUNCTION;
|
||||
void operator=(const ASTRecordLayout &) LLVM_DELETED_FUNCTION;
|
||||
public:
|
||||
|
||||
/// getAlignment - Get the record alignment in characters.
|
||||
|
@ -721,6 +721,7 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateArgument(
|
||||
case TemplateArgument::Null:
|
||||
case TemplateArgument::Declaration:
|
||||
case TemplateArgument::Integral:
|
||||
case TemplateArgument::NullPtr:
|
||||
return true;
|
||||
|
||||
case TemplateArgument::Type:
|
||||
@ -753,6 +754,7 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateArgumentLoc(
|
||||
case TemplateArgument::Null:
|
||||
case TemplateArgument::Declaration:
|
||||
case TemplateArgument::Integral:
|
||||
case TemplateArgument::NullPtr:
|
||||
return true;
|
||||
|
||||
case TemplateArgument::Type: {
|
||||
@ -799,7 +801,7 @@ bool RecursiveASTVisitor<Derived>::TraverseConstructorInitializer(
|
||||
if (TypeSourceInfo *TInfo = Init->getTypeSourceInfo())
|
||||
TRY_TO(TraverseTypeLoc(TInfo->getTypeLoc()));
|
||||
|
||||
if (Init->isWritten())
|
||||
if (Init->isWritten() || getDerived().shouldVisitImplicitCode())
|
||||
TRY_TO(TraverseStmt(Init->getInit()));
|
||||
return true;
|
||||
}
|
||||
@ -1827,7 +1829,7 @@ bool RecursiveASTVisitor<Derived>::Traverse##STMT (STMT *S) { \
|
||||
return true; \
|
||||
}
|
||||
|
||||
DEF_TRAVERSE_STMT(AsmStmt, {
|
||||
DEF_TRAVERSE_STMT(GCCAsmStmt, {
|
||||
TRY_TO(TraverseStmt(S->getAsmString()));
|
||||
for (unsigned I = 0, E = S->getNumInputs(); I < E; ++I) {
|
||||
TRY_TO(TraverseStmt(S->getInputConstraintLiteral(I)));
|
||||
@ -1836,7 +1838,7 @@ DEF_TRAVERSE_STMT(AsmStmt, {
|
||||
TRY_TO(TraverseStmt(S->getOutputConstraintLiteral(I)));
|
||||
}
|
||||
for (unsigned I = 0, E = S->getNumClobbers(); I < E; ++I) {
|
||||
TRY_TO(TraverseStmt(S->getClobber(I)));
|
||||
TRY_TO(TraverseStmt(S->getClobberStringLiteral(I)));
|
||||
}
|
||||
// children() iterates over inputExpr and outputExpr.
|
||||
})
|
||||
@ -2141,7 +2143,9 @@ DEF_TRAVERSE_STMT(BlockExpr, {
|
||||
return true; // no child statements to loop through.
|
||||
})
|
||||
DEF_TRAVERSE_STMT(ChooseExpr, { })
|
||||
DEF_TRAVERSE_STMT(CompoundLiteralExpr, { })
|
||||
DEF_TRAVERSE_STMT(CompoundLiteralExpr, {
|
||||
TRY_TO(TraverseTypeLoc(S->getTypeSourceInfo()->getTypeLoc()));
|
||||
})
|
||||
DEF_TRAVERSE_STMT(CXXBindTemporaryExpr, { })
|
||||
DEF_TRAVERSE_STMT(CXXBoolLiteralExpr, { })
|
||||
DEF_TRAVERSE_STMT(CXXDefaultArgExpr, { })
|
||||
@ -2219,6 +2223,7 @@ DEF_TRAVERSE_STMT(PackExpansionExpr, { })
|
||||
DEF_TRAVERSE_STMT(SizeOfPackExpr, { })
|
||||
DEF_TRAVERSE_STMT(SubstNonTypeTemplateParmPackExpr, { })
|
||||
DEF_TRAVERSE_STMT(SubstNonTypeTemplateParmExpr, { })
|
||||
DEF_TRAVERSE_STMT(FunctionParmPackExpr, { })
|
||||
DEF_TRAVERSE_STMT(MaterializeTemporaryExpr, { })
|
||||
DEF_TRAVERSE_STMT(AtomicExpr, { })
|
||||
|
||||
|
@ -42,7 +42,7 @@ enum SelectorLocationsKind {
|
||||
SelLoc_StandardWithSpace = 2
|
||||
};
|
||||
|
||||
/// \brief Returns true if all \arg SelLocs are in a "standard" location.
|
||||
/// \brief Returns true if all \p SelLocs are in a "standard" location.
|
||||
SelectorLocationsKind hasStandardSelectorLocs(Selector Sel,
|
||||
ArrayRef<SourceLocation> SelLocs,
|
||||
ArrayRef<Expr *> Args,
|
||||
@ -60,7 +60,7 @@ SourceLocation getStandardSelectorLoc(unsigned Index,
|
||||
ArrayRef<Expr *> Args,
|
||||
SourceLocation EndLoc);
|
||||
|
||||
/// \brief Returns true if all \arg SelLocs are in a "standard" location.
|
||||
/// \brief Returns true if all \p SelLocs are in a "standard" location.
|
||||
SelectorLocationsKind hasStandardSelectorLocs(Selector Sel,
|
||||
ArrayRef<SourceLocation> SelLocs,
|
||||
ArrayRef<ParmVarDecl *> Args,
|
||||
|
@ -392,9 +392,6 @@ class Stmt {
|
||||
const_cast<const Stmt*>(this)->stripLabelLikeStatements());
|
||||
}
|
||||
|
||||
// Implement isa<T> support.
|
||||
static bool classof(const Stmt *) { return true; }
|
||||
|
||||
/// hasImplicitControlFlow - Some statements (e.g. short circuited operations)
|
||||
/// contain implicit control-flow in the order their subexpressions
|
||||
/// are evaluated. This predicate returns true if this statement has
|
||||
@ -424,12 +421,12 @@ class Stmt {
|
||||
|
||||
/// \brief Produce a unique representation of the given statement.
|
||||
///
|
||||
/// \brief ID once the profiling operation is complete, will contain
|
||||
/// \param ID once the profiling operation is complete, will contain
|
||||
/// the unique representation of the given statement.
|
||||
///
|
||||
/// \brief Context the AST context in which the statement resides
|
||||
/// \param Context the AST context in which the statement resides
|
||||
///
|
||||
/// \brief Canonical whether the profile should be based on the canonical
|
||||
/// \param Canonical whether the profile should be based on the canonical
|
||||
/// representation of this statement (e.g., where non-type template
|
||||
/// parameters are identified by index/level rather than their
|
||||
/// declaration pointers) or the exact representation of the statement as
|
||||
@ -480,7 +477,6 @@ class DeclStmt : public Stmt {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == DeclStmtClass;
|
||||
}
|
||||
static bool classof(const DeclStmt *) { return true; }
|
||||
|
||||
// Iterators over subexpressions.
|
||||
child_range children() {
|
||||
@ -535,7 +531,6 @@ class NullStmt : public Stmt {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == NullStmtClass;
|
||||
}
|
||||
static bool classof(const NullStmt *) { return true; }
|
||||
|
||||
child_range children() { return child_range(); }
|
||||
|
||||
@ -615,7 +610,6 @@ class CompoundStmt : public Stmt {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CompoundStmtClass;
|
||||
}
|
||||
static bool classof(const CompoundStmt *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() {
|
||||
@ -654,7 +648,6 @@ class SwitchCase : public Stmt {
|
||||
return T->getStmtClass() == CaseStmtClass ||
|
||||
T->getStmtClass() == DefaultStmtClass;
|
||||
}
|
||||
static bool classof(const SwitchCase *) { return true; }
|
||||
};
|
||||
|
||||
class CaseStmt : public SwitchCase {
|
||||
@ -714,7 +707,6 @@ class CaseStmt : public SwitchCase {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CaseStmtClass;
|
||||
}
|
||||
static bool classof(const CaseStmt *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() {
|
||||
@ -749,7 +741,6 @@ class DefaultStmt : public SwitchCase {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == DefaultStmtClass;
|
||||
}
|
||||
static bool classof(const DefaultStmt *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() { return child_range(&SubStmt, &SubStmt+1); }
|
||||
@ -788,7 +779,6 @@ class LabelStmt : public Stmt {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == LabelStmtClass;
|
||||
}
|
||||
static bool classof(const LabelStmt *) { return true; }
|
||||
};
|
||||
|
||||
|
||||
@ -837,7 +827,6 @@ class AttributedStmt : public Stmt {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == AttributedStmtClass;
|
||||
}
|
||||
static bool classof(const AttributedStmt *) { return true; }
|
||||
};
|
||||
|
||||
|
||||
@ -906,7 +895,6 @@ class IfStmt : public Stmt {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == IfStmtClass;
|
||||
}
|
||||
static bool classof(const IfStmt *) { return true; }
|
||||
};
|
||||
|
||||
/// SwitchStmt - This represents a 'switch' stmt.
|
||||
@ -1000,7 +988,6 @@ class SwitchStmt : public Stmt {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == SwitchStmtClass;
|
||||
}
|
||||
static bool classof(const SwitchStmt *) { return true; }
|
||||
};
|
||||
|
||||
|
||||
@ -1050,7 +1037,6 @@ class WhileStmt : public Stmt {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == WhileStmtClass;
|
||||
}
|
||||
static bool classof(const WhileStmt *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() {
|
||||
@ -1099,7 +1085,6 @@ class DoStmt : public Stmt {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == DoStmtClass;
|
||||
}
|
||||
static bool classof(const DoStmt *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() {
|
||||
@ -1171,7 +1156,6 @@ class ForStmt : public Stmt {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ForStmtClass;
|
||||
}
|
||||
static bool classof(const ForStmt *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() {
|
||||
@ -1206,7 +1190,6 @@ class GotoStmt : public Stmt {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == GotoStmtClass;
|
||||
}
|
||||
static bool classof(const GotoStmt *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() { return child_range(); }
|
||||
@ -1251,7 +1234,6 @@ class IndirectGotoStmt : public Stmt {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == IndirectGotoStmtClass;
|
||||
}
|
||||
static bool classof(const IndirectGotoStmt *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() { return child_range(&Target, &Target+1); }
|
||||
@ -1278,7 +1260,6 @@ class ContinueStmt : public Stmt {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ContinueStmtClass;
|
||||
}
|
||||
static bool classof(const ContinueStmt *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() { return child_range(); }
|
||||
@ -1302,7 +1283,6 @@ class BreakStmt : public Stmt {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == BreakStmtClass;
|
||||
}
|
||||
static bool classof(const BreakStmt *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() { return child_range(); }
|
||||
@ -1354,7 +1334,6 @@ class ReturnStmt : public Stmt {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ReturnStmtClass;
|
||||
}
|
||||
static bool classof(const ReturnStmt *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() {
|
||||
@ -1363,48 +1342,184 @@ class ReturnStmt : public Stmt {
|
||||
}
|
||||
};
|
||||
|
||||
/// AsmStmt - This represents a GNU inline-assembly statement extension.
|
||||
/// AsmStmt is the base class for GCCAsmStmt and MSAsmStmt.
|
||||
///
|
||||
class AsmStmt : public Stmt {
|
||||
SourceLocation AsmLoc, RParenLoc;
|
||||
StringLiteral *AsmStr;
|
||||
|
||||
protected:
|
||||
SourceLocation AsmLoc;
|
||||
/// \brief True if the assembly statement does not have any input or output
|
||||
/// operands.
|
||||
bool IsSimple;
|
||||
|
||||
/// \brief If true, treat this inline assembly as having side effects.
|
||||
/// This assembly statement should not be optimized, deleted or moved.
|
||||
bool IsVolatile;
|
||||
bool MSAsm;
|
||||
|
||||
unsigned NumOutputs;
|
||||
unsigned NumInputs;
|
||||
unsigned NumClobbers;
|
||||
|
||||
// FIXME: If we wanted to, we could allocate all of these in one big array.
|
||||
IdentifierInfo **Names;
|
||||
StringLiteral **Constraints;
|
||||
Stmt **Exprs;
|
||||
StringLiteral **Clobbers;
|
||||
|
||||
AsmStmt(StmtClass SC, SourceLocation asmloc, bool issimple, bool isvolatile,
|
||||
unsigned numoutputs, unsigned numinputs, unsigned numclobbers) :
|
||||
Stmt (SC), AsmLoc(asmloc), IsSimple(issimple), IsVolatile(isvolatile),
|
||||
NumOutputs(numoutputs), NumInputs(numinputs), NumClobbers(numclobbers) { }
|
||||
|
||||
public:
|
||||
AsmStmt(ASTContext &C, SourceLocation asmloc, bool issimple, bool isvolatile,
|
||||
bool msasm, unsigned numoutputs, unsigned numinputs,
|
||||
IdentifierInfo **names, StringLiteral **constraints,
|
||||
Expr **exprs, StringLiteral *asmstr, unsigned numclobbers,
|
||||
StringLiteral **clobbers, SourceLocation rparenloc);
|
||||
|
||||
/// \brief Build an empty inline-assembly statement.
|
||||
explicit AsmStmt(EmptyShell Empty) : Stmt(AsmStmtClass, Empty),
|
||||
Names(0), Constraints(0), Exprs(0), Clobbers(0) { }
|
||||
explicit AsmStmt(StmtClass SC, EmptyShell Empty) :
|
||||
Stmt(SC, Empty), Names(0), Exprs(0) { }
|
||||
|
||||
SourceLocation getAsmLoc() const { return AsmLoc; }
|
||||
void setAsmLoc(SourceLocation L) { AsmLoc = L; }
|
||||
SourceLocation getRParenLoc() const { return RParenLoc; }
|
||||
void setRParenLoc(SourceLocation L) { RParenLoc = L; }
|
||||
|
||||
bool isSimple() const { return IsSimple; }
|
||||
void setSimple(bool V) { IsSimple = V; }
|
||||
|
||||
bool isVolatile() const { return IsVolatile; }
|
||||
void setVolatile(bool V) { IsVolatile = V; }
|
||||
bool isSimple() const { return IsSimple; }
|
||||
void setSimple(bool V) { IsSimple = V; }
|
||||
bool isMSAsm() const { return MSAsm; }
|
||||
void setMSAsm(bool V) { MSAsm = V; }
|
||||
|
||||
SourceRange getSourceRange() const LLVM_READONLY { return SourceRange(); }
|
||||
|
||||
//===--- Asm String Analysis ---===//
|
||||
|
||||
/// Assemble final IR asm string.
|
||||
std::string generateAsmString(ASTContext &C) const;
|
||||
|
||||
//===--- Output operands ---===//
|
||||
|
||||
unsigned getNumOutputs() const { return NumOutputs; }
|
||||
|
||||
IdentifierInfo *getOutputIdentifier(unsigned i) const {
|
||||
return Names[i];
|
||||
}
|
||||
|
||||
StringRef getOutputName(unsigned i) const {
|
||||
if (IdentifierInfo *II = getOutputIdentifier(i))
|
||||
return II->getName();
|
||||
|
||||
return StringRef();
|
||||
}
|
||||
|
||||
/// getOutputConstraint - Return the constraint string for the specified
|
||||
/// output operand. All output constraints are known to be non-empty (either
|
||||
/// '=' or '+').
|
||||
StringRef getOutputConstraint(unsigned i) const;
|
||||
|
||||
/// isOutputPlusConstraint - Return true if the specified output constraint
|
||||
/// is a "+" constraint (which is both an input and an output) or false if it
|
||||
/// is an "=" constraint (just an output).
|
||||
bool isOutputPlusConstraint(unsigned i) const {
|
||||
return getOutputConstraint(i)[0] == '+';
|
||||
}
|
||||
|
||||
const Expr *getOutputExpr(unsigned i) const;
|
||||
|
||||
/// getNumPlusOperands - Return the number of output operands that have a "+"
|
||||
/// constraint.
|
||||
unsigned getNumPlusOperands() const;
|
||||
|
||||
//===--- Input operands ---===//
|
||||
|
||||
unsigned getNumInputs() const { return NumInputs; }
|
||||
|
||||
IdentifierInfo *getInputIdentifier(unsigned i) const {
|
||||
return Names[i + NumOutputs];
|
||||
}
|
||||
|
||||
StringRef getInputName(unsigned i) const {
|
||||
if (IdentifierInfo *II = getInputIdentifier(i))
|
||||
return II->getName();
|
||||
|
||||
return StringRef();
|
||||
}
|
||||
|
||||
/// getInputConstraint - Return the specified input constraint. Unlike output
|
||||
/// constraints, these can be empty.
|
||||
StringRef getInputConstraint(unsigned i) const;
|
||||
|
||||
const Expr *getInputExpr(unsigned i) const;
|
||||
|
||||
//===--- Other ---===//
|
||||
|
||||
unsigned getNumClobbers() const { return NumClobbers; }
|
||||
StringRef getClobber(unsigned i) const;
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == GCCAsmStmtClass ||
|
||||
T->getStmtClass() == MSAsmStmtClass;
|
||||
}
|
||||
|
||||
// Input expr iterators.
|
||||
|
||||
typedef ExprIterator inputs_iterator;
|
||||
typedef ConstExprIterator const_inputs_iterator;
|
||||
|
||||
inputs_iterator begin_inputs() {
|
||||
return &Exprs[0] + NumOutputs;
|
||||
}
|
||||
|
||||
inputs_iterator end_inputs() {
|
||||
return &Exprs[0] + NumOutputs + NumInputs;
|
||||
}
|
||||
|
||||
const_inputs_iterator begin_inputs() const {
|
||||
return &Exprs[0] + NumOutputs;
|
||||
}
|
||||
|
||||
const_inputs_iterator end_inputs() const {
|
||||
return &Exprs[0] + NumOutputs + NumInputs;
|
||||
}
|
||||
|
||||
// Output expr iterators.
|
||||
|
||||
typedef ExprIterator outputs_iterator;
|
||||
typedef ConstExprIterator const_outputs_iterator;
|
||||
|
||||
outputs_iterator begin_outputs() {
|
||||
return &Exprs[0];
|
||||
}
|
||||
outputs_iterator end_outputs() {
|
||||
return &Exprs[0] + NumOutputs;
|
||||
}
|
||||
|
||||
const_outputs_iterator begin_outputs() const {
|
||||
return &Exprs[0];
|
||||
}
|
||||
const_outputs_iterator end_outputs() const {
|
||||
return &Exprs[0] + NumOutputs;
|
||||
}
|
||||
|
||||
child_range children() {
|
||||
return child_range(&Exprs[0], &Exprs[0] + NumOutputs + NumInputs);
|
||||
}
|
||||
};
|
||||
|
||||
/// This represents a GCC inline-assembly statement extension.
|
||||
///
|
||||
class GCCAsmStmt : public AsmStmt {
|
||||
SourceLocation RParenLoc;
|
||||
StringLiteral *AsmStr;
|
||||
|
||||
// FIXME: If we wanted to, we could allocate all of these in one big array.
|
||||
StringLiteral **Constraints;
|
||||
StringLiteral **Clobbers;
|
||||
|
||||
public:
|
||||
GCCAsmStmt(ASTContext &C, SourceLocation asmloc, bool issimple,
|
||||
bool isvolatile, unsigned numoutputs, unsigned numinputs,
|
||||
IdentifierInfo **names, StringLiteral **constraints, Expr **exprs,
|
||||
StringLiteral *asmstr, unsigned numclobbers,
|
||||
StringLiteral **clobbers, SourceLocation rparenloc);
|
||||
|
||||
/// \brief Build an empty inline-assembly statement.
|
||||
explicit GCCAsmStmt(EmptyShell Empty) : AsmStmt(GCCAsmStmtClass, Empty),
|
||||
Constraints(0), Clobbers(0) { }
|
||||
|
||||
SourceLocation getRParenLoc() const { return RParenLoc; }
|
||||
void setRParenLoc(SourceLocation L) { RParenLoc = L; }
|
||||
|
||||
//===--- Asm String Analysis ---===//
|
||||
|
||||
@ -1461,25 +1576,11 @@ class AsmStmt : public Stmt {
|
||||
unsigned AnalyzeAsmString(SmallVectorImpl<AsmStringPiece> &Pieces,
|
||||
ASTContext &C, unsigned &DiagOffs) const;
|
||||
|
||||
/// Assemble final IR asm string.
|
||||
std::string generateAsmString(ASTContext &C) const;
|
||||
|
||||
//===--- Output operands ---===//
|
||||
|
||||
unsigned getNumOutputs() const { return NumOutputs; }
|
||||
|
||||
IdentifierInfo *getOutputIdentifier(unsigned i) const {
|
||||
return Names[i];
|
||||
}
|
||||
|
||||
StringRef getOutputName(unsigned i) const {
|
||||
if (IdentifierInfo *II = getOutputIdentifier(i))
|
||||
return II->getName();
|
||||
|
||||
return StringRef();
|
||||
}
|
||||
|
||||
/// getOutputConstraint - Return the constraint string for the specified
|
||||
/// output operand. All output constraints are known to be non-empty (either
|
||||
/// '=' or '+').
|
||||
StringRef getOutputConstraint(unsigned i) const;
|
||||
|
||||
const StringLiteral *getOutputConstraintLiteral(unsigned i) const {
|
||||
@ -1492,37 +1593,11 @@ class AsmStmt : public Stmt {
|
||||
Expr *getOutputExpr(unsigned i);
|
||||
|
||||
const Expr *getOutputExpr(unsigned i) const {
|
||||
return const_cast<AsmStmt*>(this)->getOutputExpr(i);
|
||||
return const_cast<GCCAsmStmt*>(this)->getOutputExpr(i);
|
||||
}
|
||||
|
||||
/// isOutputPlusConstraint - Return true if the specified output constraint
|
||||
/// is a "+" constraint (which is both an input and an output) or false if it
|
||||
/// is an "=" constraint (just an output).
|
||||
bool isOutputPlusConstraint(unsigned i) const {
|
||||
return getOutputConstraint(i)[0] == '+';
|
||||
}
|
||||
|
||||
/// getNumPlusOperands - Return the number of output operands that have a "+"
|
||||
/// constraint.
|
||||
unsigned getNumPlusOperands() const;
|
||||
|
||||
//===--- Input operands ---===//
|
||||
|
||||
unsigned getNumInputs() const { return NumInputs; }
|
||||
|
||||
IdentifierInfo *getInputIdentifier(unsigned i) const {
|
||||
return Names[i + NumOutputs];
|
||||
}
|
||||
|
||||
StringRef getInputName(unsigned i) const {
|
||||
if (IdentifierInfo *II = getInputIdentifier(i))
|
||||
return II->getName();
|
||||
|
||||
return StringRef();
|
||||
}
|
||||
|
||||
/// getInputConstraint - Return the specified input constraint. Unlike output
|
||||
/// constraints, these can be empty.
|
||||
StringRef getInputConstraint(unsigned i) const;
|
||||
|
||||
const StringLiteral *getInputConstraintLiteral(unsigned i) const {
|
||||
@ -1536,7 +1611,7 @@ class AsmStmt : public Stmt {
|
||||
void setInputExpr(unsigned i, Expr *E);
|
||||
|
||||
const Expr *getInputExpr(unsigned i) const {
|
||||
return const_cast<AsmStmt*>(this)->getInputExpr(i);
|
||||
return const_cast<GCCAsmStmt*>(this)->getInputExpr(i);
|
||||
}
|
||||
|
||||
void setOutputsAndInputsAndClobbers(ASTContext &C,
|
||||
@ -1555,90 +1630,45 @@ class AsmStmt : public Stmt {
|
||||
/// This returns -1 if the operand name is invalid.
|
||||
int getNamedOperand(StringRef SymbolicName) const;
|
||||
|
||||
unsigned getNumClobbers() const { return NumClobbers; }
|
||||
StringLiteral *getClobber(unsigned i) { return Clobbers[i]; }
|
||||
const StringLiteral *getClobber(unsigned i) const { return Clobbers[i]; }
|
||||
StringRef getClobber(unsigned i) const;
|
||||
StringLiteral *getClobberStringLiteral(unsigned i) { return Clobbers[i]; }
|
||||
const StringLiteral *getClobberStringLiteral(unsigned i) const {
|
||||
return Clobbers[i];
|
||||
}
|
||||
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
return SourceRange(AsmLoc, RParenLoc);
|
||||
}
|
||||
|
||||
static bool classof(const Stmt *T) {return T->getStmtClass() == AsmStmtClass;}
|
||||
static bool classof(const AsmStmt *) { return true; }
|
||||
|
||||
// Input expr iterators.
|
||||
|
||||
typedef ExprIterator inputs_iterator;
|
||||
typedef ConstExprIterator const_inputs_iterator;
|
||||
|
||||
inputs_iterator begin_inputs() {
|
||||
return &Exprs[0] + NumOutputs;
|
||||
}
|
||||
|
||||
inputs_iterator end_inputs() {
|
||||
return &Exprs[0] + NumOutputs + NumInputs;
|
||||
}
|
||||
|
||||
const_inputs_iterator begin_inputs() const {
|
||||
return &Exprs[0] + NumOutputs;
|
||||
}
|
||||
|
||||
const_inputs_iterator end_inputs() const {
|
||||
return &Exprs[0] + NumOutputs + NumInputs;
|
||||
}
|
||||
|
||||
// Output expr iterators.
|
||||
|
||||
typedef ExprIterator outputs_iterator;
|
||||
typedef ConstExprIterator const_outputs_iterator;
|
||||
|
||||
outputs_iterator begin_outputs() {
|
||||
return &Exprs[0];
|
||||
}
|
||||
outputs_iterator end_outputs() {
|
||||
return &Exprs[0] + NumOutputs;
|
||||
}
|
||||
|
||||
const_outputs_iterator begin_outputs() const {
|
||||
return &Exprs[0];
|
||||
}
|
||||
const_outputs_iterator end_outputs() const {
|
||||
return &Exprs[0] + NumOutputs;
|
||||
}
|
||||
|
||||
child_range children() {
|
||||
return child_range(&Exprs[0], &Exprs[0] + NumOutputs + NumInputs);
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == GCCAsmStmtClass;
|
||||
}
|
||||
};
|
||||
|
||||
/// MSAsmStmt - This represents a MS inline-assembly statement extension.
|
||||
/// This represents a Microsoft inline-assembly statement extension.
|
||||
///
|
||||
class MSAsmStmt : public Stmt {
|
||||
class MSAsmStmt : public AsmStmt {
|
||||
SourceLocation AsmLoc, LBraceLoc, EndLoc;
|
||||
std::string AsmStr;
|
||||
|
||||
bool IsSimple;
|
||||
bool IsVolatile;
|
||||
|
||||
unsigned NumAsmToks;
|
||||
unsigned NumInputs;
|
||||
unsigned NumOutputs;
|
||||
unsigned NumClobbers;
|
||||
|
||||
Token *AsmToks;
|
||||
IdentifierInfo **Names;
|
||||
Stmt **Exprs;
|
||||
StringRef *Constraints;
|
||||
StringRef *Clobbers;
|
||||
|
||||
public:
|
||||
MSAsmStmt(ASTContext &C, SourceLocation asmloc, SourceLocation lbraceloc,
|
||||
bool issimple, bool isvolatile, ArrayRef<Token> asmtoks,
|
||||
ArrayRef<IdentifierInfo*> inputs, ArrayRef<IdentifierInfo*> outputs,
|
||||
StringRef asmstr, ArrayRef<StringRef> clobbers,
|
||||
SourceLocation endloc);
|
||||
unsigned numoutputs, unsigned numinputs,
|
||||
ArrayRef<IdentifierInfo*> names, ArrayRef<StringRef> constraints,
|
||||
ArrayRef<Expr*> exprs, StringRef asmstr,
|
||||
ArrayRef<StringRef> clobbers, SourceLocation endloc);
|
||||
|
||||
/// \brief Build an empty MS-style inline-assembly statement.
|
||||
explicit MSAsmStmt(EmptyShell Empty) : AsmStmt(MSAsmStmtClass, Empty),
|
||||
NumAsmToks(0), AsmToks(0), Constraints(0), Clobbers(0) { }
|
||||
|
||||
SourceLocation getAsmLoc() const { return AsmLoc; }
|
||||
void setAsmLoc(SourceLocation L) { AsmLoc = L; }
|
||||
SourceLocation getLBraceLoc() const { return LBraceLoc; }
|
||||
void setLBraceLoc(SourceLocation L) { LBraceLoc = L; }
|
||||
SourceLocation getEndLoc() const { return EndLoc; }
|
||||
@ -1649,20 +1679,42 @@ class MSAsmStmt : public Stmt {
|
||||
unsigned getNumAsmToks() { return NumAsmToks; }
|
||||
Token *getAsmToks() { return AsmToks; }
|
||||
|
||||
bool isVolatile() const { return IsVolatile; }
|
||||
void setVolatile(bool V) { IsVolatile = V; }
|
||||
bool isSimple() const { return IsSimple; }
|
||||
void setSimple(bool V) { IsSimple = V; }
|
||||
|
||||
//===--- Asm String Analysis ---===//
|
||||
|
||||
const std::string *getAsmString() const { return &AsmStr; }
|
||||
std::string *getAsmString() { return &AsmStr; }
|
||||
void setAsmString(StringRef &E) { AsmStr = E.str(); }
|
||||
|
||||
/// Assemble final IR asm string.
|
||||
std::string generateAsmString(ASTContext &C) const;
|
||||
|
||||
//===--- Output operands ---===//
|
||||
|
||||
StringRef getOutputConstraint(unsigned i) const {
|
||||
return Constraints[i];
|
||||
}
|
||||
|
||||
Expr *getOutputExpr(unsigned i);
|
||||
|
||||
const Expr *getOutputExpr(unsigned i) const {
|
||||
return const_cast<MSAsmStmt*>(this)->getOutputExpr(i);
|
||||
}
|
||||
|
||||
//===--- Input operands ---===//
|
||||
|
||||
StringRef getInputConstraint(unsigned i) const {
|
||||
return Constraints[i + NumOutputs];
|
||||
}
|
||||
|
||||
Expr *getInputExpr(unsigned i);
|
||||
void setInputExpr(unsigned i, Expr *E);
|
||||
|
||||
const Expr *getInputExpr(unsigned i) const {
|
||||
return const_cast<MSAsmStmt*>(this)->getInputExpr(i);
|
||||
}
|
||||
|
||||
//===--- Other ---===//
|
||||
|
||||
unsigned getNumClobbers() const { return NumClobbers; }
|
||||
StringRef getClobber(unsigned i) const { return Clobbers[i]; }
|
||||
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
@ -1671,7 +1723,6 @@ class MSAsmStmt : public Stmt {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == MSAsmStmtClass;
|
||||
}
|
||||
static bool classof(const MSAsmStmt *) { return true; }
|
||||
|
||||
child_range children() {
|
||||
return child_range(&Exprs[0], &Exprs[0]);
|
||||
@ -1720,8 +1771,6 @@ class SEHExceptStmt : public Stmt {
|
||||
return T->getStmtClass() == SEHExceptStmtClass;
|
||||
}
|
||||
|
||||
static bool classof(SEHExceptStmt *) { return true; }
|
||||
|
||||
};
|
||||
|
||||
class SEHFinallyStmt : public Stmt {
|
||||
@ -1757,8 +1806,6 @@ class SEHFinallyStmt : public Stmt {
|
||||
return T->getStmtClass() == SEHFinallyStmtClass;
|
||||
}
|
||||
|
||||
static bool classof(SEHFinallyStmt *) { return true; }
|
||||
|
||||
};
|
||||
|
||||
class SEHTryStmt : public Stmt {
|
||||
@ -1810,8 +1857,6 @@ class SEHTryStmt : public Stmt {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == SEHTryStmtClass;
|
||||
}
|
||||
|
||||
static bool classof(SEHTryStmt *) { return true; }
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
@ -50,7 +50,6 @@ class CXXCatchStmt : public Stmt {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CXXCatchStmtClass;
|
||||
}
|
||||
static bool classof(const CXXCatchStmt *) { return true; }
|
||||
|
||||
child_range children() { return child_range(&HandlerBlock, &HandlerBlock+1); }
|
||||
|
||||
@ -111,7 +110,6 @@ class CXXTryStmt : public Stmt {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CXXTryStmtClass;
|
||||
}
|
||||
static bool classof(const CXXTryStmt *) { return true; }
|
||||
|
||||
child_range children() {
|
||||
return child_range(getStmts(), getStmts() + getNumHandlers() + 1);
|
||||
@ -196,7 +194,6 @@ class CXXForRangeStmt : public Stmt {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CXXForRangeStmtClass;
|
||||
}
|
||||
static bool classof(const CXXForRangeStmt *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() {
|
||||
@ -286,8 +283,6 @@ class MSDependentExistsStmt : public Stmt {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == MSDependentExistsStmtClass;
|
||||
}
|
||||
|
||||
static bool classof(MSDependentExistsStmt *) { return true; }
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
@ -61,7 +61,6 @@ class ObjCForCollectionStmt : public Stmt {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCForCollectionStmtClass;
|
||||
}
|
||||
static bool classof(const ObjCForCollectionStmt *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() {
|
||||
@ -112,7 +111,6 @@ class ObjCAtCatchStmt : public Stmt {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCAtCatchStmtClass;
|
||||
}
|
||||
static bool classof(const ObjCAtCatchStmt *) { return true; }
|
||||
|
||||
child_range children() { return child_range(&Body, &Body + 1); }
|
||||
};
|
||||
@ -143,7 +141,6 @@ class ObjCAtFinallyStmt : public Stmt {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCAtFinallyStmtClass;
|
||||
}
|
||||
static bool classof(const ObjCAtFinallyStmt *) { return true; }
|
||||
|
||||
child_range children() {
|
||||
return child_range(&AtFinallyStmt, &AtFinallyStmt+1);
|
||||
@ -244,7 +241,6 @@ class ObjCAtTryStmt : public Stmt {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCAtTryStmtClass;
|
||||
}
|
||||
static bool classof(const ObjCAtTryStmt *) { return true; }
|
||||
|
||||
child_range children() {
|
||||
return child_range(getStmts(),
|
||||
@ -303,7 +299,6 @@ class ObjCAtSynchronizedStmt : public Stmt {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCAtSynchronizedStmtClass;
|
||||
}
|
||||
static bool classof(const ObjCAtSynchronizedStmt *) { return true; }
|
||||
|
||||
child_range children() {
|
||||
return child_range(&SubStmts[0], &SubStmts[0]+END_EXPR);
|
||||
@ -339,7 +334,6 @@ class ObjCAtThrowStmt : public Stmt {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCAtThrowStmtClass;
|
||||
}
|
||||
static bool classof(const ObjCAtThrowStmt *) { return true; }
|
||||
|
||||
child_range children() { return child_range(&Throw, &Throw+1); }
|
||||
};
|
||||
@ -371,7 +365,6 @@ class ObjCAutoreleasePoolStmt : public Stmt {
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCAutoreleasePoolStmtClass;
|
||||
}
|
||||
static bool classof(const ObjCAutoreleasePoolStmt *) { return true; }
|
||||
|
||||
child_range children() { return child_range(&SubStmt, &SubStmt + 1); }
|
||||
};
|
||||
|
@ -28,11 +28,11 @@ namespace llvm {
|
||||
|
||||
namespace clang {
|
||||
|
||||
class Decl;
|
||||
class DiagnosticBuilder;
|
||||
class Expr;
|
||||
struct PrintingPolicy;
|
||||
class TypeSourceInfo;
|
||||
class ValueDecl;
|
||||
|
||||
/// \brief Represents a template argument within a class template
|
||||
/// specialization.
|
||||
@ -43,12 +43,14 @@ class TemplateArgument {
|
||||
/// \brief Represents an empty template argument, e.g., one that has not
|
||||
/// been deduced.
|
||||
Null = 0,
|
||||
/// The template argument is a type. Its value is stored in the
|
||||
/// TypeOrValue field.
|
||||
/// The template argument is a type.
|
||||
Type,
|
||||
/// The template argument is a declaration that was provided for a pointer
|
||||
/// or reference non-type template parameter.
|
||||
/// The template argument is a declaration that was provided for a pointer,
|
||||
/// reference, or pointer to member non-type template parameter.
|
||||
Declaration,
|
||||
/// The template argument is a null pointer or null pointer to member that
|
||||
/// was provided for a non-type template parameter.
|
||||
NullPtr,
|
||||
/// The template argument is an integral value stored in an llvm::APSInt
|
||||
/// that was provided for an integral non-type template parameter.
|
||||
Integral,
|
||||
@ -72,6 +74,10 @@ class TemplateArgument {
|
||||
|
||||
union {
|
||||
uintptr_t TypeOrValue;
|
||||
struct {
|
||||
ValueDecl *D;
|
||||
bool ForRefParam;
|
||||
} DeclArg;
|
||||
struct {
|
||||
// We store a decomposed APSInt with the data allocated by ASTContext if
|
||||
// BitWidth > 64. The memory may be shared between multiple
|
||||
@ -101,15 +107,18 @@ class TemplateArgument {
|
||||
TemplateArgument() : Kind(Null), TypeOrValue(0) { }
|
||||
|
||||
/// \brief Construct a template type argument.
|
||||
TemplateArgument(QualType T) : Kind(Type) {
|
||||
TemplateArgument(QualType T, bool isNullPtr = false)
|
||||
: Kind(isNullPtr ? NullPtr : Type) {
|
||||
TypeOrValue = reinterpret_cast<uintptr_t>(T.getAsOpaquePtr());
|
||||
}
|
||||
|
||||
/// \brief Construct a template argument that refers to a
|
||||
/// declaration, which is either an external declaration or a
|
||||
/// template declaration.
|
||||
TemplateArgument(Decl *D) : Kind(Declaration) {
|
||||
TypeOrValue = reinterpret_cast<uintptr_t>(D);
|
||||
TemplateArgument(ValueDecl *D, bool ForRefParam) : Kind(Declaration) {
|
||||
assert(D && "Expected decl");
|
||||
DeclArg.D = D;
|
||||
DeclArg.ForRefParam = ForRefParam;
|
||||
}
|
||||
|
||||
/// \brief Construct an integral constant template argument. The memory to
|
||||
@ -177,6 +186,10 @@ class TemplateArgument {
|
||||
this->Args.NumArgs = NumArgs;
|
||||
}
|
||||
|
||||
static TemplateArgument getEmptyPack() {
|
||||
return TemplateArgument((TemplateArgument*)0, 0);
|
||||
}
|
||||
|
||||
/// \brief Create a new template argument pack by copying the given set of
|
||||
/// template arguments.
|
||||
static TemplateArgument CreatePackCopy(ASTContext &Context,
|
||||
@ -205,34 +218,43 @@ class TemplateArgument {
|
||||
/// \brief Determine whether this template argument is a pack expansion.
|
||||
bool isPackExpansion() const;
|
||||
|
||||
/// \brief Retrieve the template argument as a type.
|
||||
/// \brief Retrieve the type for a type template argument.
|
||||
QualType getAsType() const {
|
||||
if (Kind != Type)
|
||||
return QualType();
|
||||
|
||||
assert(Kind == Type && "Unexpected kind");
|
||||
return QualType::getFromOpaquePtr(reinterpret_cast<void*>(TypeOrValue));
|
||||
}
|
||||
|
||||
/// \brief Retrieve the template argument as a declaration.
|
||||
Decl *getAsDecl() const {
|
||||
if (Kind != Declaration)
|
||||
return 0;
|
||||
return reinterpret_cast<Decl *>(TypeOrValue);
|
||||
/// \brief Retrieve the declaration for a declaration non-type
|
||||
/// template argument.
|
||||
ValueDecl *getAsDecl() const {
|
||||
assert(Kind == Declaration && "Unexpected kind");
|
||||
return DeclArg.D;
|
||||
}
|
||||
|
||||
/// \brief Retrieve the template argument as a template name.
|
||||
/// \brief Retrieve whether a declaration is binding to a
|
||||
/// reference parameter in a declaration non-type template argument.
|
||||
bool isDeclForReferenceParam() const {
|
||||
assert(Kind == Declaration && "Unexpected kind");
|
||||
return DeclArg.ForRefParam;
|
||||
}
|
||||
|
||||
/// \brief Retrieve the type for null non-type template argument.
|
||||
QualType getNullPtrType() const {
|
||||
assert(Kind == NullPtr && "Unexpected kind");
|
||||
return QualType::getFromOpaquePtr(reinterpret_cast<void*>(TypeOrValue));
|
||||
}
|
||||
|
||||
/// \brief Retrieve the template name for a template name argument.
|
||||
TemplateName getAsTemplate() const {
|
||||
if (Kind != Template)
|
||||
return TemplateName();
|
||||
|
||||
assert(Kind == Template && "Unexpected kind");
|
||||
return TemplateName::getFromVoidPointer(TemplateArg.Name);
|
||||
}
|
||||
|
||||
/// \brief Retrieve the template argument as a template name; if the argument
|
||||
/// is a pack expansion, return the pattern as a template name.
|
||||
TemplateName getAsTemplateOrTemplatePattern() const {
|
||||
if (Kind != Template && Kind != TemplateExpansion)
|
||||
return TemplateName();
|
||||
assert((Kind == Template || Kind == TemplateExpansion) &&
|
||||
"Unexpected kind");
|
||||
|
||||
return TemplateName::getFromVoidPointer(TemplateArg.Name);
|
||||
}
|
||||
@ -244,6 +266,7 @@ class TemplateArgument {
|
||||
/// \brief Retrieve the template argument as an integral value.
|
||||
// FIXME: Provide a way to read the integral data without copying the value.
|
||||
llvm::APSInt getAsIntegral() const {
|
||||
assert(Kind == Integral && "Unexpected kind");
|
||||
using namespace llvm;
|
||||
if (Integer.BitWidth <= 64)
|
||||
return APSInt(APInt(Integer.BitWidth, Integer.VAL), Integer.IsUnsigned);
|
||||
@ -255,23 +278,18 @@ class TemplateArgument {
|
||||
|
||||
/// \brief Retrieve the type of the integral value.
|
||||
QualType getIntegralType() const {
|
||||
if (Kind != Integral)
|
||||
return QualType();
|
||||
|
||||
assert(Kind == Integral && "Unexpected kind");
|
||||
return QualType::getFromOpaquePtr(Integer.Type);
|
||||
}
|
||||
|
||||
void setIntegralType(QualType T) {
|
||||
assert(Kind == Integral &&
|
||||
"Cannot set the integral type of a non-integral template argument");
|
||||
assert(Kind == Integral && "Unexpected kind");
|
||||
Integer.Type = T.getAsOpaquePtr();
|
||||
}
|
||||
|
||||
/// \brief Retrieve the template argument as an expression.
|
||||
Expr *getAsExpr() const {
|
||||
if (Kind != Expression)
|
||||
return 0;
|
||||
|
||||
assert(Kind == Expression && "Unexpected kind");
|
||||
return reinterpret_cast<Expr *>(TypeOrValue);
|
||||
}
|
||||
|
||||
@ -436,7 +454,17 @@ class TemplateArgumentLoc {
|
||||
assert(Argument.getKind() == TemplateArgument::Declaration);
|
||||
return LocInfo.getAsExpr();
|
||||
}
|
||||
|
||||
|
||||
Expr *getSourceNullPtrExpression() const {
|
||||
assert(Argument.getKind() == TemplateArgument::NullPtr);
|
||||
return LocInfo.getAsExpr();
|
||||
}
|
||||
|
||||
Expr *getSourceIntegralExpression() const {
|
||||
assert(Argument.getKind() == TemplateArgument::Integral);
|
||||
return LocInfo.getAsExpr();
|
||||
}
|
||||
|
||||
NestedNameSpecifierLoc getTemplateQualifierLoc() const {
|
||||
assert(Argument.getKind() == TemplateArgument::Template ||
|
||||
Argument.getKind() == TemplateArgument::TemplateExpansion);
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "clang/Basic/Linkage.h"
|
||||
#include "clang/Basic/PartialDiagnostic.h"
|
||||
#include "clang/Basic/Visibility.h"
|
||||
#include "clang/Basic/Specifiers.h"
|
||||
#include "clang/AST/NestedNameSpecifier.h"
|
||||
#include "clang/AST/TemplateName.h"
|
||||
#include "llvm/Support/type_traits.h"
|
||||
@ -160,6 +161,44 @@ class Qualifiers {
|
||||
|
||||
Qualifiers() : Mask(0) {}
|
||||
|
||||
/// \brief Returns the common set of qualifiers while removing them from
|
||||
/// the given sets.
|
||||
static Qualifiers removeCommonQualifiers(Qualifiers &L, Qualifiers &R) {
|
||||
// If both are only CVR-qualified, bit operations are sufficient.
|
||||
if (!(L.Mask & ~CVRMask) && !(R.Mask & ~CVRMask)) {
|
||||
Qualifiers Q;
|
||||
Q.Mask = L.Mask & R.Mask;
|
||||
L.Mask &= ~Q.Mask;
|
||||
R.Mask &= ~Q.Mask;
|
||||
return Q;
|
||||
}
|
||||
|
||||
Qualifiers Q;
|
||||
unsigned CommonCRV = L.getCVRQualifiers() & R.getCVRQualifiers();
|
||||
Q.addCVRQualifiers(CommonCRV);
|
||||
L.removeCVRQualifiers(CommonCRV);
|
||||
R.removeCVRQualifiers(CommonCRV);
|
||||
|
||||
if (L.getObjCGCAttr() == R.getObjCGCAttr()) {
|
||||
Q.setObjCGCAttr(L.getObjCGCAttr());
|
||||
L.removeObjCGCAttr();
|
||||
R.removeObjCGCAttr();
|
||||
}
|
||||
|
||||
if (L.getObjCLifetime() == R.getObjCLifetime()) {
|
||||
Q.setObjCLifetime(L.getObjCLifetime());
|
||||
L.removeObjCLifetime();
|
||||
R.removeObjCLifetime();
|
||||
}
|
||||
|
||||
if (L.getAddressSpace() == R.getAddressSpace()) {
|
||||
Q.setAddressSpace(L.getAddressSpace());
|
||||
L.removeAddressSpace();
|
||||
R.removeAddressSpace();
|
||||
}
|
||||
return Q;
|
||||
}
|
||||
|
||||
static Qualifiers fromFastMask(unsigned Mask) {
|
||||
Qualifiers Qs;
|
||||
Qs.addFastQualifiers(Mask);
|
||||
@ -333,6 +372,23 @@ class Qualifiers {
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Remove the qualifiers from the given set from this set.
|
||||
void removeQualifiers(Qualifiers Q) {
|
||||
// If the other set doesn't have any non-boolean qualifiers, just
|
||||
// bit-and the inverse in.
|
||||
if (!(Q.Mask & ~CVRMask))
|
||||
Mask &= ~Q.Mask;
|
||||
else {
|
||||
Mask &= ~(Q.Mask & CVRMask);
|
||||
if (getObjCGCAttr() == Q.getObjCGCAttr())
|
||||
removeObjCGCAttr();
|
||||
if (getObjCLifetime() == Q.getObjCLifetime())
|
||||
removeObjCLifetime();
|
||||
if (getAddressSpace() == Q.getAddressSpace())
|
||||
removeAddressSpace();
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Add the qualifiers from the given set to this set, given that
|
||||
/// they don't conflict.
|
||||
void addConsistentQualifiers(Qualifiers qs) {
|
||||
@ -400,7 +456,7 @@ class Qualifiers {
|
||||
}
|
||||
|
||||
Qualifiers &operator-=(Qualifiers R) {
|
||||
Mask = Mask & ~(R.Mask);
|
||||
removeQualifiers(R);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -435,18 +491,6 @@ class Qualifiers {
|
||||
static const uint32_t AddressSpaceShift = 8;
|
||||
};
|
||||
|
||||
/// CallingConv - Specifies the calling convention that a function uses.
|
||||
enum CallingConv {
|
||||
CC_Default,
|
||||
CC_C, // __attribute__((cdecl))
|
||||
CC_X86StdCall, // __attribute__((stdcall))
|
||||
CC_X86FastCall, // __attribute__((fastcall))
|
||||
CC_X86ThisCall, // __attribute__((thiscall))
|
||||
CC_X86Pascal, // __attribute__((pascal))
|
||||
CC_AAPCS, // __attribute__((pcs("aapcs")))
|
||||
CC_AAPCS_VFP // __attribute__((pcs("aapcs-vfp")))
|
||||
};
|
||||
|
||||
/// A std::pair-like structure for storing a qualified type split
|
||||
/// into its local qualifiers and its locally-unqualified type.
|
||||
struct SplitQualType {
|
||||
@ -1126,8 +1170,8 @@ class Type : public ExtQualsTypeCommonBase {
|
||||
};
|
||||
|
||||
private:
|
||||
Type(const Type&); // DO NOT IMPLEMENT.
|
||||
void operator=(const Type&); // DO NOT IMPLEMENT.
|
||||
Type(const Type &) LLVM_DELETED_FUNCTION;
|
||||
void operator=(const Type &) LLVM_DELETED_FUNCTION;
|
||||
|
||||
/// Bitfields required by the Type class.
|
||||
class TypeBitfields {
|
||||
@ -1225,7 +1269,7 @@ class Type : public ExtQualsTypeCommonBase {
|
||||
|
||||
/// Extra information which affects how the function is called, like
|
||||
/// regparm and the calling convention.
|
||||
unsigned ExtInfo : 8;
|
||||
unsigned ExtInfo : 9;
|
||||
|
||||
/// TypeQuals - Used only by FunctionProtoType, put here to pack with the
|
||||
/// other bitfields.
|
||||
@ -1512,6 +1556,7 @@ class Type : public ExtQualsTypeCommonBase {
|
||||
bool isRecordType() const;
|
||||
bool isClassType() const;
|
||||
bool isStructureType() const;
|
||||
bool isInterfaceType() const;
|
||||
bool isStructureOrClassType() const;
|
||||
bool isUnionType() const;
|
||||
bool isComplexIntegerType() const; // GCC _Complex integer type.
|
||||
@ -1630,13 +1675,19 @@ class Type : public ExtQualsTypeCommonBase {
|
||||
const ObjCObjectPointerType *getAsObjCQualifiedIdType() const;
|
||||
const ObjCObjectPointerType *getAsObjCQualifiedClassType() const;
|
||||
const ObjCObjectType *getAsObjCQualifiedInterfaceType() const;
|
||||
const CXXRecordDecl *getCXXRecordDeclForPointerType() const;
|
||||
|
||||
/// \brief Retrieves the CXXRecordDecl that this type refers to, either
|
||||
/// because the type is a RecordType or because it is the injected-class-name
|
||||
/// type of a class template or class template partial specialization.
|
||||
CXXRecordDecl *getAsCXXRecordDecl() const;
|
||||
|
||||
/// If this is a pointer or reference to a RecordType, return the
|
||||
/// CXXRecordDecl that that type refers to.
|
||||
///
|
||||
/// If this is not a pointer or reference, or the type being pointed to does
|
||||
/// not refer to a CXXRecordDecl, returns NULL.
|
||||
const CXXRecordDecl *getPointeeCXXRecordDecl() const;
|
||||
|
||||
/// \brief Get the AutoType whose type will be deduced for a variable with
|
||||
/// an initializer of this type. This looks through declarators like pointer
|
||||
/// types, but not through decltype or typedefs.
|
||||
@ -1738,8 +1789,6 @@ class Type : public ExtQualsTypeCommonBase {
|
||||
CanQualType getCanonicalTypeUnqualified() const; // in CanonicalType.h
|
||||
LLVM_ATTRIBUTE_USED void dump() const;
|
||||
|
||||
static bool classof(const Type *) { return true; }
|
||||
|
||||
friend class ASTReader;
|
||||
friend class ASTWriter;
|
||||
};
|
||||
@ -1748,6 +1797,11 @@ class Type : public ExtQualsTypeCommonBase {
|
||||
/// until it reaches a TypedefType or a non-sugared type.
|
||||
template <> const TypedefType *Type::getAs() const;
|
||||
|
||||
/// \brief This will check for a TemplateSpecializationType by removing any
|
||||
/// existing sugar until it reaches a TemplateSpecializationType or a
|
||||
/// non-sugared type.
|
||||
template <> const TemplateSpecializationType *Type::getAs() const;
|
||||
|
||||
// We can do canonical leaf types faster, because we don't have to
|
||||
// worry about preserving child type decoration.
|
||||
#define TYPE(Class, Base)
|
||||
@ -1834,7 +1888,6 @@ class BuiltinType : public Type {
|
||||
}
|
||||
|
||||
static bool classof(const Type *T) { return T->getTypeClass() == Builtin; }
|
||||
static bool classof(const BuiltinType *) { return true; }
|
||||
};
|
||||
|
||||
/// ComplexType - C99 6.2.5p11 - Complex values. This supports the C99 complex
|
||||
@ -1865,7 +1918,6 @@ class ComplexType : public Type, public llvm::FoldingSetNode {
|
||||
}
|
||||
|
||||
static bool classof(const Type *T) { return T->getTypeClass() == Complex; }
|
||||
static bool classof(const ComplexType *) { return true; }
|
||||
};
|
||||
|
||||
/// ParenType - Sugar for parentheses used when specifying types.
|
||||
@ -1897,7 +1949,6 @@ class ParenType : public Type, public llvm::FoldingSetNode {
|
||||
}
|
||||
|
||||
static bool classof(const Type *T) { return T->getTypeClass() == Paren; }
|
||||
static bool classof(const ParenType *) { return true; }
|
||||
};
|
||||
|
||||
/// PointerType - C99 6.7.5.1 - Pointer Declarators.
|
||||
@ -1929,7 +1980,6 @@ class PointerType : public Type, public llvm::FoldingSetNode {
|
||||
}
|
||||
|
||||
static bool classof(const Type *T) { return T->getTypeClass() == Pointer; }
|
||||
static bool classof(const PointerType *) { return true; }
|
||||
};
|
||||
|
||||
/// BlockPointerType - pointer to a block type.
|
||||
@ -1965,7 +2015,6 @@ class BlockPointerType : public Type, public llvm::FoldingSetNode {
|
||||
static bool classof(const Type *T) {
|
||||
return T->getTypeClass() == BlockPointer;
|
||||
}
|
||||
static bool classof(const BlockPointerType *) { return true; }
|
||||
};
|
||||
|
||||
/// ReferenceType - Base for LValueReferenceType and RValueReferenceType
|
||||
@ -2013,7 +2062,6 @@ class ReferenceType : public Type, public llvm::FoldingSetNode {
|
||||
return T->getTypeClass() == LValueReference ||
|
||||
T->getTypeClass() == RValueReference;
|
||||
}
|
||||
static bool classof(const ReferenceType *) { return true; }
|
||||
};
|
||||
|
||||
/// LValueReferenceType - C++ [dcl.ref] - Lvalue reference
|
||||
@ -2031,7 +2079,6 @@ class LValueReferenceType : public ReferenceType {
|
||||
static bool classof(const Type *T) {
|
||||
return T->getTypeClass() == LValueReference;
|
||||
}
|
||||
static bool classof(const LValueReferenceType *) { return true; }
|
||||
};
|
||||
|
||||
/// RValueReferenceType - C++0x [dcl.ref] - Rvalue reference
|
||||
@ -2048,7 +2095,6 @@ class RValueReferenceType : public ReferenceType {
|
||||
static bool classof(const Type *T) {
|
||||
return T->getTypeClass() == RValueReference;
|
||||
}
|
||||
static bool classof(const RValueReferenceType *) { return true; }
|
||||
};
|
||||
|
||||
/// MemberPointerType - C++ 8.3.3 - Pointers to members
|
||||
@ -2103,7 +2149,6 @@ class MemberPointerType : public Type, public llvm::FoldingSetNode {
|
||||
static bool classof(const Type *T) {
|
||||
return T->getTypeClass() == MemberPointer;
|
||||
}
|
||||
static bool classof(const MemberPointerType *) { return true; }
|
||||
};
|
||||
|
||||
/// ArrayType - C99 6.7.5.2 - Array Declarators.
|
||||
@ -2159,7 +2204,6 @@ class ArrayType : public Type, public llvm::FoldingSetNode {
|
||||
T->getTypeClass() == IncompleteArray ||
|
||||
T->getTypeClass() == DependentSizedArray;
|
||||
}
|
||||
static bool classof(const ArrayType *) { return true; }
|
||||
};
|
||||
|
||||
/// ConstantArrayType - This class represents the canonical version of
|
||||
@ -2211,7 +2255,6 @@ class ConstantArrayType : public ArrayType {
|
||||
static bool classof(const Type *T) {
|
||||
return T->getTypeClass() == ConstantArray;
|
||||
}
|
||||
static bool classof(const ConstantArrayType *) { return true; }
|
||||
};
|
||||
|
||||
/// IncompleteArrayType - This class represents C arrays with an unspecified
|
||||
@ -2231,7 +2274,6 @@ class IncompleteArrayType : public ArrayType {
|
||||
static bool classof(const Type *T) {
|
||||
return T->getTypeClass() == IncompleteArray;
|
||||
}
|
||||
static bool classof(const IncompleteArrayType *) { return true; }
|
||||
|
||||
friend class StmtIteratorBase;
|
||||
|
||||
@ -2294,7 +2336,6 @@ class VariableArrayType : public ArrayType {
|
||||
static bool classof(const Type *T) {
|
||||
return T->getTypeClass() == VariableArray;
|
||||
}
|
||||
static bool classof(const VariableArrayType *) { return true; }
|
||||
|
||||
friend class StmtIteratorBase;
|
||||
|
||||
@ -2351,7 +2392,6 @@ class DependentSizedArrayType : public ArrayType {
|
||||
static bool classof(const Type *T) {
|
||||
return T->getTypeClass() == DependentSizedArray;
|
||||
}
|
||||
static bool classof(const DependentSizedArrayType *) { return true; }
|
||||
|
||||
friend class StmtIteratorBase;
|
||||
|
||||
@ -2397,7 +2437,6 @@ class DependentSizedExtVectorType : public Type, public llvm::FoldingSetNode {
|
||||
static bool classof(const Type *T) {
|
||||
return T->getTypeClass() == DependentSizedExtVector;
|
||||
}
|
||||
static bool classof(const DependentSizedExtVectorType *) { return true; }
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID) {
|
||||
Profile(ID, Context, getElementType(), getSizeExpr());
|
||||
@ -2463,7 +2502,6 @@ class VectorType : public Type, public llvm::FoldingSetNode {
|
||||
static bool classof(const Type *T) {
|
||||
return T->getTypeClass() == Vector || T->getTypeClass() == ExtVector;
|
||||
}
|
||||
static bool classof(const VectorType *) { return true; }
|
||||
};
|
||||
|
||||
/// ExtVectorType - Extended vector type. This type is created using
|
||||
@ -2529,7 +2567,6 @@ class ExtVectorType : public VectorType {
|
||||
static bool classof(const Type *T) {
|
||||
return T->getTypeClass() == ExtVector;
|
||||
}
|
||||
static bool classof(const ExtVectorType *) { return true; }
|
||||
};
|
||||
|
||||
/// FunctionType - C99 6.7.5.3 - Function Declarators. This is the common base
|
||||
@ -2561,19 +2598,19 @@ class FunctionType : public Type {
|
||||
// * AST read and write
|
||||
// * Codegen
|
||||
class ExtInfo {
|
||||
// Feel free to rearrange or add bits, but if you go over 8,
|
||||
// Feel free to rearrange or add bits, but if you go over 9,
|
||||
// you'll need to adjust both the Bits field below and
|
||||
// Type::FunctionTypeBitfields.
|
||||
|
||||
// | CC |noreturn|produces|regparm|
|
||||
// |0 .. 2| 3 | 4 | 5 .. 7|
|
||||
// |0 .. 3| 4 | 5 | 6 .. 8|
|
||||
//
|
||||
// regparm is either 0 (no regparm attribute) or the regparm value+1.
|
||||
enum { CallConvMask = 0x7 };
|
||||
enum { NoReturnMask = 0x8 };
|
||||
enum { ProducesResultMask = 0x10 };
|
||||
enum { CallConvMask = 0xF };
|
||||
enum { NoReturnMask = 0x10 };
|
||||
enum { ProducesResultMask = 0x20 };
|
||||
enum { RegParmMask = ~(CallConvMask | NoReturnMask | ProducesResultMask),
|
||||
RegParmOffset = 5 }; // Assumed to be the last field
|
||||
RegParmOffset = 6 }; // Assumed to be the last field
|
||||
|
||||
uint16_t Bits;
|
||||
|
||||
@ -2692,7 +2729,6 @@ class FunctionType : public Type {
|
||||
return T->getTypeClass() == FunctionNoProto ||
|
||||
T->getTypeClass() == FunctionProto;
|
||||
}
|
||||
static bool classof(const FunctionType *) { return true; }
|
||||
};
|
||||
|
||||
/// FunctionNoProtoType - Represents a K&R-style 'int foo()' function, which has
|
||||
@ -2724,7 +2760,6 @@ class FunctionNoProtoType : public FunctionType, public llvm::FoldingSetNode {
|
||||
static bool classof(const Type *T) {
|
||||
return T->getTypeClass() == FunctionNoProto;
|
||||
}
|
||||
static bool classof(const FunctionNoProtoType *) { return true; }
|
||||
};
|
||||
|
||||
/// FunctionProtoType - Represents a prototype with argument type info, e.g.
|
||||
@ -2972,14 +3007,13 @@ class FunctionProtoType : public FunctionType, public llvm::FoldingSetNode {
|
||||
|
||||
// FIXME: Remove the string version.
|
||||
void printExceptionSpecification(std::string &S,
|
||||
PrintingPolicy Policy) const;
|
||||
const PrintingPolicy &Policy) const;
|
||||
void printExceptionSpecification(raw_ostream &OS,
|
||||
PrintingPolicy Policy) const;
|
||||
const PrintingPolicy &Policy) const;
|
||||
|
||||
static bool classof(const Type *T) {
|
||||
return T->getTypeClass() == FunctionProto;
|
||||
}
|
||||
static bool classof(const FunctionProtoType *) { return true; }
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx);
|
||||
static void Profile(llvm::FoldingSetNodeID &ID, QualType Result,
|
||||
@ -3010,7 +3044,6 @@ class UnresolvedUsingType : public Type {
|
||||
static bool classof(const Type *T) {
|
||||
return T->getTypeClass() == UnresolvedUsing;
|
||||
}
|
||||
static bool classof(const UnresolvedUsingType *) { return true; }
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID) {
|
||||
return Profile(ID, Decl);
|
||||
@ -3042,7 +3075,6 @@ class TypedefType : public Type {
|
||||
QualType desugar() const;
|
||||
|
||||
static bool classof(const Type *T) { return T->getTypeClass() == Typedef; }
|
||||
static bool classof(const TypedefType *) { return true; }
|
||||
};
|
||||
|
||||
/// TypeOfExprType (GCC extension).
|
||||
@ -3062,7 +3094,6 @@ class TypeOfExprType : public Type {
|
||||
bool isSugared() const;
|
||||
|
||||
static bool classof(const Type *T) { return T->getTypeClass() == TypeOfExpr; }
|
||||
static bool classof(const TypeOfExprType *) { return true; }
|
||||
};
|
||||
|
||||
/// \brief Internal representation of canonical, dependent
|
||||
@ -3109,7 +3140,6 @@ class TypeOfType : public Type {
|
||||
bool isSugared() const { return true; }
|
||||
|
||||
static bool classof(const Type *T) { return T->getTypeClass() == TypeOf; }
|
||||
static bool classof(const TypeOfType *) { return true; }
|
||||
};
|
||||
|
||||
/// DecltypeType (C++0x)
|
||||
@ -3131,7 +3161,6 @@ class DecltypeType : public Type {
|
||||
bool isSugared() const;
|
||||
|
||||
static bool classof(const Type *T) { return T->getTypeClass() == Decltype; }
|
||||
static bool classof(const DecltypeType *) { return true; }
|
||||
};
|
||||
|
||||
/// \brief Internal representation of canonical, dependent
|
||||
@ -3184,7 +3213,6 @@ class UnaryTransformType : public Type {
|
||||
static bool classof(const Type *T) {
|
||||
return T->getTypeClass() == UnaryTransform;
|
||||
}
|
||||
static bool classof(const UnaryTransformType *) { return true; }
|
||||
};
|
||||
|
||||
class TagType : public Type {
|
||||
@ -3207,7 +3235,6 @@ class TagType : public Type {
|
||||
static bool classof(const Type *T) {
|
||||
return T->getTypeClass() >= TagFirst && T->getTypeClass() <= TagLast;
|
||||
}
|
||||
static bool classof(const TagType *) { return true; }
|
||||
};
|
||||
|
||||
/// RecordType - This is a helper class that allows the use of isa/cast/dyncast
|
||||
@ -3234,7 +3261,6 @@ class RecordType : public TagType {
|
||||
QualType desugar() const { return QualType(this, 0); }
|
||||
|
||||
static bool classof(const Type *T) { return T->getTypeClass() == Record; }
|
||||
static bool classof(const RecordType *) { return true; }
|
||||
};
|
||||
|
||||
/// EnumType - This is a helper class that allows the use of isa/cast/dyncast
|
||||
@ -3253,7 +3279,6 @@ class EnumType : public TagType {
|
||||
QualType desugar() const { return QualType(this, 0); }
|
||||
|
||||
static bool classof(const Type *T) { return T->getTypeClass() == Enum; }
|
||||
static bool classof(const EnumType *) { return true; }
|
||||
};
|
||||
|
||||
/// AttributedType - An attributed type is a type to which a type
|
||||
@ -3297,7 +3322,8 @@ class AttributedType : public Type, public llvm::FoldingSetNode {
|
||||
attr_fastcall,
|
||||
attr_stdcall,
|
||||
attr_thiscall,
|
||||
attr_pascal
|
||||
attr_pascal,
|
||||
attr_pnaclcall
|
||||
};
|
||||
|
||||
private:
|
||||
@ -3341,7 +3367,6 @@ class AttributedType : public Type, public llvm::FoldingSetNode {
|
||||
static bool classof(const Type *T) {
|
||||
return T->getTypeClass() == Attributed;
|
||||
}
|
||||
static bool classof(const AttributedType *T) { return true; }
|
||||
};
|
||||
|
||||
class TemplateTypeParmType : public Type, public llvm::FoldingSetNode {
|
||||
@ -3415,7 +3440,6 @@ class TemplateTypeParmType : public Type, public llvm::FoldingSetNode {
|
||||
static bool classof(const Type *T) {
|
||||
return T->getTypeClass() == TemplateTypeParm;
|
||||
}
|
||||
static bool classof(const TemplateTypeParmType *T) { return true; }
|
||||
};
|
||||
|
||||
/// \brief Represents the result of substituting a type for a template
|
||||
@ -3466,7 +3490,6 @@ class SubstTemplateTypeParmType : public Type, public llvm::FoldingSetNode {
|
||||
static bool classof(const Type *T) {
|
||||
return T->getTypeClass() == SubstTemplateTypeParm;
|
||||
}
|
||||
static bool classof(const SubstTemplateTypeParmType *T) { return true; }
|
||||
};
|
||||
|
||||
/// \brief Represents the result of substituting a set of types for a template
|
||||
@ -3519,7 +3542,6 @@ class SubstTemplateTypeParmPackType : public Type, public llvm::FoldingSetNode {
|
||||
static bool classof(const Type *T) {
|
||||
return T->getTypeClass() == SubstTemplateTypeParmPack;
|
||||
}
|
||||
static bool classof(const SubstTemplateTypeParmPackType *T) { return true; }
|
||||
};
|
||||
|
||||
/// \brief Represents a C++0x auto type.
|
||||
@ -3562,7 +3584,6 @@ class AutoType : public Type, public llvm::FoldingSetNode {
|
||||
static bool classof(const Type *T) {
|
||||
return T->getTypeClass() == Auto;
|
||||
}
|
||||
static bool classof(const AutoType *T) { return true; }
|
||||
};
|
||||
|
||||
/// \brief Represents a type template specialization; the template
|
||||
@ -3726,7 +3747,6 @@ class TemplateSpecializationType
|
||||
static bool classof(const Type *T) {
|
||||
return T->getTypeClass() == TemplateSpecialization;
|
||||
}
|
||||
static bool classof(const TemplateSpecializationType *T) { return true; }
|
||||
};
|
||||
|
||||
/// \brief The injected class name of a C++ class template or class
|
||||
@ -3789,13 +3809,14 @@ class InjectedClassNameType : public Type {
|
||||
static bool classof(const Type *T) {
|
||||
return T->getTypeClass() == InjectedClassName;
|
||||
}
|
||||
static bool classof(const InjectedClassNameType *T) { return true; }
|
||||
};
|
||||
|
||||
/// \brief The kind of a tag type.
|
||||
enum TagTypeKind {
|
||||
/// \brief The "struct" keyword.
|
||||
TTK_Struct,
|
||||
/// \brief The "__interface" keyword.
|
||||
TTK_Interface,
|
||||
/// \brief The "union" keyword.
|
||||
TTK_Union,
|
||||
/// \brief The "class" keyword.
|
||||
@ -3809,6 +3830,8 @@ enum TagTypeKind {
|
||||
enum ElaboratedTypeKeyword {
|
||||
/// \brief The "struct" keyword introduces the elaborated-type-specifier.
|
||||
ETK_Struct,
|
||||
/// \brief The "__interface" keyword introduces the elaborated-type-specifier.
|
||||
ETK_Interface,
|
||||
/// \brief The "union" keyword introduces the elaborated-type-specifier.
|
||||
ETK_Union,
|
||||
/// \brief The "class" keyword introduces the elaborated-type-specifier.
|
||||
@ -3932,7 +3955,6 @@ class ElaboratedType : public TypeWithKeyword, public llvm::FoldingSetNode {
|
||||
static bool classof(const Type *T) {
|
||||
return T->getTypeClass() == Elaborated;
|
||||
}
|
||||
static bool classof(const ElaboratedType *T) { return true; }
|
||||
};
|
||||
|
||||
/// \brief Represents a qualified type name for which the type name is
|
||||
@ -3996,7 +4018,6 @@ class DependentNameType : public TypeWithKeyword, public llvm::FoldingSetNode {
|
||||
static bool classof(const Type *T) {
|
||||
return T->getTypeClass() == DependentName;
|
||||
}
|
||||
static bool classof(const DependentNameType *T) { return true; }
|
||||
};
|
||||
|
||||
/// DependentTemplateSpecializationType - Represents a template
|
||||
@ -4067,9 +4088,6 @@ class DependentTemplateSpecializationType :
|
||||
static bool classof(const Type *T) {
|
||||
return T->getTypeClass() == DependentTemplateSpecialization;
|
||||
}
|
||||
static bool classof(const DependentTemplateSpecializationType *T) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief Represents a pack expansion of types.
|
||||
@ -4150,9 +4168,6 @@ class PackExpansionType : public Type, public llvm::FoldingSetNode {
|
||||
static bool classof(const Type *T) {
|
||||
return T->getTypeClass() == PackExpansion;
|
||||
}
|
||||
static bool classof(const PackExpansionType *T) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
/// ObjCObjectType - Represents a class type in Objective C.
|
||||
@ -4263,7 +4278,6 @@ class ObjCObjectType : public Type {
|
||||
return T->getTypeClass() == ObjCObject ||
|
||||
T->getTypeClass() == ObjCInterface;
|
||||
}
|
||||
static bool classof(const ObjCObjectType *) { return true; }
|
||||
};
|
||||
|
||||
/// ObjCObjectTypeImpl - A class providing a concrete implementation
|
||||
@ -4327,7 +4341,6 @@ class ObjCInterfaceType : public ObjCObjectType {
|
||||
static bool classof(const Type *T) {
|
||||
return T->getTypeClass() == ObjCInterface;
|
||||
}
|
||||
static bool classof(const ObjCInterfaceType *) { return true; }
|
||||
|
||||
// Nonsense to "hide" certain members of ObjCObjectType within this
|
||||
// class. People asking for protocols on an ObjCInterfaceType are
|
||||
@ -4477,7 +4490,6 @@ class ObjCObjectPointerType : public Type, public llvm::FoldingSetNode {
|
||||
static bool classof(const Type *T) {
|
||||
return T->getTypeClass() == ObjCObjectPointer;
|
||||
}
|
||||
static bool classof(const ObjCObjectPointerType *) { return true; }
|
||||
};
|
||||
|
||||
class AtomicType : public Type, public llvm::FoldingSetNode {
|
||||
@ -4508,7 +4520,6 @@ class AtomicType : public Type, public llvm::FoldingSetNode {
|
||||
static bool classof(const Type *T) {
|
||||
return T->getTypeClass() == Atomic;
|
||||
}
|
||||
static bool classof(const AtomicType *) { return true; }
|
||||
};
|
||||
|
||||
/// A qualifier set is used to build a set of qualifiers.
|
||||
|
@ -159,8 +159,6 @@ class TypeLoc {
|
||||
return !(LHS == RHS);
|
||||
}
|
||||
|
||||
static bool classof(const TypeLoc *TL) { return true; }
|
||||
|
||||
private:
|
||||
static void initializeImpl(ASTContext &Context, TypeLoc TL,
|
||||
SourceLocation Loc);
|
||||
@ -192,7 +190,6 @@ class UnqualTypeLoc : public TypeLoc {
|
||||
static bool classof(const TypeLoc *TL) {
|
||||
return !TL->getType().hasLocalQualifiers();
|
||||
}
|
||||
static bool classof(const UnqualTypeLoc *TL) { return true; }
|
||||
};
|
||||
|
||||
/// \brief Wrapper of type source information for a type with
|
||||
@ -237,7 +234,6 @@ class QualifiedTypeLoc : public TypeLoc {
|
||||
static bool classof(const TypeLoc *TL) {
|
||||
return TL->getType().hasLocalQualifiers();
|
||||
}
|
||||
static bool classof(const QualifiedTypeLoc *TL) { return true; }
|
||||
};
|
||||
|
||||
inline UnqualTypeLoc TypeLoc::getUnqualifiedLoc() const {
|
||||
@ -250,11 +246,11 @@ inline UnqualTypeLoc TypeLoc::getUnqualifiedLoc() const {
|
||||
/// to a particular Type subclass. It is accepted for a single
|
||||
/// TypeLoc class to correspond to multiple Type classes.
|
||||
///
|
||||
/// \param Base a class from which to derive
|
||||
/// \param Derived the class deriving from this one
|
||||
/// \param TypeClass the concrete Type subclass associated with this
|
||||
/// \tparam Base a class from which to derive
|
||||
/// \tparam Derived the class deriving from this one
|
||||
/// \tparam TypeClass the concrete Type subclass associated with this
|
||||
/// location type
|
||||
/// \param LocalData the structure type of local location data for
|
||||
/// \tparam LocalData the structure type of local location data for
|
||||
/// this type
|
||||
///
|
||||
/// sizeof(LocalData) needs to be a multiple of sizeof(void*) or
|
||||
@ -303,9 +299,6 @@ class ConcreteTypeLoc : public Base {
|
||||
static bool classof(const UnqualTypeLoc *TL) {
|
||||
return Derived::classofType(TL->getTypePtr());
|
||||
}
|
||||
static bool classof(const Derived *TL) {
|
||||
return true;
|
||||
}
|
||||
|
||||
TypeLoc getNextTypeLoc() const {
|
||||
return getNextTypeLoc(asDerived()->getInnerType());
|
||||
@ -380,9 +373,6 @@ class InheritingConcreteTypeLoc : public Base {
|
||||
static bool classof(const UnqualTypeLoc *TL) {
|
||||
return Derived::classofType(TL->getTypePtr());
|
||||
}
|
||||
static bool classof(const Derived *TL) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const TypeClass *getTypePtr() const {
|
||||
return cast<TypeClass>(Base::getTypePtr());
|
||||
@ -417,7 +407,6 @@ class TypeSpecTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc,
|
||||
}
|
||||
|
||||
static bool classof(const TypeLoc *TL);
|
||||
static bool classof(const TypeSpecTypeLoc *TL) { return true; }
|
||||
};
|
||||
|
||||
|
||||
@ -866,6 +855,7 @@ class ObjCInterfaceTypeLoc : public ConcreteTypeLoc<ObjCObjectTypeLoc,
|
||||
|
||||
void initializeLocal(ASTContext &Context, SourceLocation Loc) {
|
||||
setNameLoc(Loc);
|
||||
setNameEndLoc(Loc);
|
||||
}
|
||||
};
|
||||
|
||||
@ -1060,6 +1050,8 @@ class RValueReferenceTypeLoc :
|
||||
|
||||
struct FunctionLocInfo {
|
||||
SourceLocation LocalRangeBegin;
|
||||
SourceLocation LParenLoc;
|
||||
SourceLocation RParenLoc;
|
||||
SourceLocation LocalRangeEnd;
|
||||
};
|
||||
|
||||
@ -1083,6 +1075,24 @@ class FunctionTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc,
|
||||
getLocalData()->LocalRangeEnd = L;
|
||||
}
|
||||
|
||||
SourceLocation getLParenLoc() const {
|
||||
return this->getLocalData()->LParenLoc;
|
||||
}
|
||||
void setLParenLoc(SourceLocation Loc) {
|
||||
this->getLocalData()->LParenLoc = Loc;
|
||||
}
|
||||
|
||||
SourceLocation getRParenLoc() const {
|
||||
return this->getLocalData()->RParenLoc;
|
||||
}
|
||||
void setRParenLoc(SourceLocation Loc) {
|
||||
this->getLocalData()->RParenLoc = Loc;
|
||||
}
|
||||
|
||||
SourceRange getParensRange() const {
|
||||
return SourceRange(getLParenLoc(), getRParenLoc());
|
||||
}
|
||||
|
||||
ArrayRef<ParmVarDecl *> getParams() const {
|
||||
return ArrayRef<ParmVarDecl *>(getParmArray(), getNumArgs());
|
||||
}
|
||||
@ -1110,6 +1120,8 @@ class FunctionTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc,
|
||||
|
||||
void initializeLocal(ASTContext &Context, SourceLocation Loc) {
|
||||
setLocalRangeBegin(Loc);
|
||||
setLParenLoc(Loc);
|
||||
setRParenLoc(Loc);
|
||||
setLocalRangeEnd(Loc);
|
||||
for (unsigned i = 0, e = getNumArgs(); i != e; ++i)
|
||||
setArg(i, NULL);
|
||||
|
@ -94,7 +94,7 @@ class UnresolvedSetImpl {
|
||||
private:
|
||||
template <unsigned N> friend class UnresolvedSet;
|
||||
UnresolvedSetImpl() {}
|
||||
UnresolvedSetImpl(const UnresolvedSetImpl &) {}
|
||||
UnresolvedSetImpl(const UnresolvedSetImpl &) LLVM_DELETED_FUNCTION;
|
||||
|
||||
public:
|
||||
// We don't currently support assignment through this iterator, so we might
|
||||
|
@ -147,9 +147,10 @@ class VTableComponent {
|
||||
assert((ComponentKind == CK_VCallOffset ||
|
||||
ComponentKind == CK_VBaseOffset ||
|
||||
ComponentKind == CK_OffsetToTop) && "Invalid component kind!");
|
||||
assert(Offset.getQuantity() <= ((1LL << 56) - 1) && "Offset is too big!");
|
||||
assert(Offset.getQuantity() < (1LL << 56) && "Offset is too big!");
|
||||
assert(Offset.getQuantity() >= -(1LL << 56) && "Offset is too small!");
|
||||
|
||||
Value = ((Offset.getQuantity() << 3) | ComponentKind);
|
||||
Value = (uint64_t(Offset.getQuantity()) << 3) | ComponentKind;
|
||||
}
|
||||
|
||||
VTableComponent(Kind ComponentKind, uintptr_t Ptr) {
|
||||
|
@ -85,7 +85,14 @@ class MatchFinder {
|
||||
class MatchCallback {
|
||||
public:
|
||||
virtual ~MatchCallback();
|
||||
|
||||
/// \brief Called on every match by the \c MatchFinder.
|
||||
virtual void run(const MatchResult &Result) = 0;
|
||||
|
||||
/// \brief Called at the start of each translation unit.
|
||||
///
|
||||
/// Optionally override to do per translation unit tasks.
|
||||
virtual void onStartOfTranslationUnit() {}
|
||||
};
|
||||
|
||||
/// \brief Called when parsing is finished. Intended for testing only.
|
||||
@ -112,11 +119,24 @@ class MatchFinder {
|
||||
MatchCallback *Action);
|
||||
void addMatcher(const StatementMatcher &NodeMatch,
|
||||
MatchCallback *Action);
|
||||
void addMatcher(const NestedNameSpecifierMatcher &NodeMatch,
|
||||
MatchCallback *Action);
|
||||
void addMatcher(const NestedNameSpecifierLocMatcher &NodeMatch,
|
||||
MatchCallback *Action);
|
||||
void addMatcher(const TypeLocMatcher &NodeMatch,
|
||||
MatchCallback *Action);
|
||||
/// @}
|
||||
|
||||
/// \brief Creates a clang ASTConsumer that finds all matches.
|
||||
clang::ASTConsumer *newASTConsumer();
|
||||
|
||||
/// \brief Finds all matches on the given \c Node.
|
||||
///
|
||||
/// @{
|
||||
void findAll(const Decl &Node, ASTContext &Context);
|
||||
void findAll(const Stmt &Node, ASTContext &Context);
|
||||
/// @}
|
||||
|
||||
/// \brief Registers a callback to notify the end of parsing.
|
||||
///
|
||||
/// The provided closure is called after parsing is done, before the AST is
|
||||
@ -125,11 +145,10 @@ class MatchFinder {
|
||||
void registerTestCallbackAfterParsing(ParsingDoneTestCallback *ParsingDone);
|
||||
|
||||
private:
|
||||
/// \brief The MatchCallback*'s will be called every time the
|
||||
/// UntypedBaseMatcher matches on the AST.
|
||||
std::vector< std::pair<
|
||||
const internal::UntypedBaseMatcher*,
|
||||
MatchCallback*> > Triggers;
|
||||
/// \brief For each \c DynTypedMatcher a \c MatchCallback that will be called
|
||||
/// when it matches.
|
||||
std::vector<std::pair<const internal::DynTypedMatcher*, MatchCallback*> >
|
||||
MatcherCallbackPairs;
|
||||
|
||||
/// \brief Called when parsing is done.
|
||||
ParsingDoneTestCallback *ParsingDone;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -39,7 +39,11 @@
|
||||
#include "clang/AST/DeclCXX.h"
|
||||
#include "clang/AST/ExprCXX.h"
|
||||
#include "clang/AST/Stmt.h"
|
||||
#include "clang/AST/StmtCXX.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/ASTMatchers/ASTTypeTraits.h"
|
||||
#include "llvm/ADT/VariadicFunction.h"
|
||||
#include "llvm/Support/type_traits.h"
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@ -57,6 +61,45 @@ class BoundNodes;
|
||||
namespace internal {
|
||||
|
||||
class BoundNodesTreeBuilder;
|
||||
/// \brief Internal version of BoundNodes. Holds all the bound nodes.
|
||||
class BoundNodesMap {
|
||||
public:
|
||||
/// \brief Adds \c Node to the map with key \c ID.
|
||||
///
|
||||
/// The node's base type should be in NodeBaseType or it will be unaccessible.
|
||||
template <typename T>
|
||||
void addNode(StringRef ID, const T* Node) {
|
||||
NodeMap[ID] = ast_type_traits::DynTypedNode::create(*Node);
|
||||
}
|
||||
void addNode(StringRef ID, ast_type_traits::DynTypedNode Node) {
|
||||
NodeMap[ID] = Node;
|
||||
}
|
||||
|
||||
/// \brief Returns the AST node bound to \c ID.
|
||||
///
|
||||
/// Returns NULL if there was no node bound to \c ID or if there is a node but
|
||||
/// it cannot be converted to the specified type.
|
||||
template <typename T>
|
||||
const T *getNodeAs(StringRef ID) const {
|
||||
IDToNodeMap::const_iterator It = NodeMap.find(ID);
|
||||
if (It == NodeMap.end()) {
|
||||
return NULL;
|
||||
}
|
||||
return It->second.get<T>();
|
||||
}
|
||||
|
||||
/// \brief Copies all ID/Node pairs to BoundNodesTreeBuilder \c Builder.
|
||||
void copyTo(BoundNodesTreeBuilder *Builder) const;
|
||||
|
||||
/// \brief Copies all ID/Node pairs to BoundNodesMap \c Other.
|
||||
void copyTo(BoundNodesMap *Other) const;
|
||||
|
||||
private:
|
||||
/// \brief A map from IDs to the bound nodes.
|
||||
typedef std::map<std::string, ast_type_traits::DynTypedNode> IDToNodeMap;
|
||||
|
||||
IDToNodeMap NodeMap;
|
||||
};
|
||||
|
||||
/// \brief A tree of bound nodes in match results.
|
||||
///
|
||||
@ -84,11 +127,10 @@ class BoundNodesTree {
|
||||
BoundNodesTree();
|
||||
|
||||
/// \brief Create a BoundNodesTree from pre-filled maps of bindings.
|
||||
BoundNodesTree(const std::map<std::string, const Decl*>& DeclBindings,
|
||||
const std::map<std::string, const Stmt*>& StmtBindings,
|
||||
BoundNodesTree(const BoundNodesMap& Bindings,
|
||||
const std::vector<BoundNodesTree> RecursiveBindings);
|
||||
|
||||
/// \brief Adds all bound nodes to bound_nodes_builder.
|
||||
/// \brief Adds all bound nodes to \c Builder.
|
||||
void copyTo(BoundNodesTreeBuilder* Builder) const;
|
||||
|
||||
/// \brief Visits all matches that this BoundNodesTree represents.
|
||||
@ -99,17 +141,12 @@ class BoundNodesTree {
|
||||
private:
|
||||
void visitMatchesRecursively(
|
||||
Visitor* ResultVistior,
|
||||
std::map<std::string, const Decl*> DeclBindings,
|
||||
std::map<std::string, const Stmt*> StmtBindings);
|
||||
|
||||
template <typename T>
|
||||
void copyBindingsTo(const T& bindings, BoundNodesTreeBuilder* Builder) const;
|
||||
const BoundNodesMap& AggregatedBindings);
|
||||
|
||||
// FIXME: Find out whether we want to use different data structures here -
|
||||
// first benchmarks indicate that it doesn't matter though.
|
||||
|
||||
std::map<std::string, const Decl*> DeclBindings;
|
||||
std::map<std::string, const Stmt*> StmtBindings;
|
||||
BoundNodesMap Bindings;
|
||||
|
||||
std::vector<BoundNodesTree> RecursiveBindings;
|
||||
};
|
||||
@ -123,12 +160,13 @@ class BoundNodesTreeBuilder {
|
||||
BoundNodesTreeBuilder();
|
||||
|
||||
/// \brief Add a binding from an id to a node.
|
||||
///
|
||||
/// FIXME: Add overloads for all AST base types.
|
||||
/// @{
|
||||
void setBinding(const std::string &Id, const Decl *Node);
|
||||
void setBinding(const std::string &Id, const Stmt *Node);
|
||||
/// @}
|
||||
template <typename T>
|
||||
void setBinding(const std::string &Id, const T *Node) {
|
||||
Bindings.addNode(Id, Node);
|
||||
}
|
||||
void setBinding(const std::string &Id, ast_type_traits::DynTypedNode Node) {
|
||||
Bindings.addNode(Id, Node);
|
||||
}
|
||||
|
||||
/// \brief Adds a branch in the tree.
|
||||
void addMatch(const BoundNodesTree& Bindings);
|
||||
@ -137,11 +175,10 @@ class BoundNodesTreeBuilder {
|
||||
BoundNodesTree build() const;
|
||||
|
||||
private:
|
||||
BoundNodesTreeBuilder(const BoundNodesTreeBuilder&); // DO NOT IMPLEMENT
|
||||
void operator=(const BoundNodesTreeBuilder&); // DO NOT IMPLEMENT
|
||||
BoundNodesTreeBuilder(const BoundNodesTreeBuilder &) LLVM_DELETED_FUNCTION;
|
||||
void operator=(const BoundNodesTreeBuilder &) LLVM_DELETED_FUNCTION;
|
||||
|
||||
std::map<std::string, const Decl*> DeclBindings;
|
||||
std::map<std::string, const Stmt*> StmtBindings;
|
||||
BoundNodesMap Bindings;
|
||||
|
||||
std::vector<BoundNodesTree> RecursiveBindings;
|
||||
};
|
||||
@ -169,7 +206,8 @@ class MatcherInterface : public llvm::RefCountedBaseVPTR {
|
||||
BoundNodesTreeBuilder *Builder) const = 0;
|
||||
};
|
||||
|
||||
/// \brief Interface for matchers that only evaluate properties on a single node.
|
||||
/// \brief Interface for matchers that only evaluate properties on a single
|
||||
/// node.
|
||||
template <typename T>
|
||||
class SingleNodeMatcherInterface : public MatcherInterface<T> {
|
||||
public:
|
||||
@ -187,6 +225,24 @@ class SingleNodeMatcherInterface : public MatcherInterface<T> {
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief Base class for all matchers that works on a \c DynTypedNode.
|
||||
///
|
||||
/// Matcher implementations will check whether the \c DynTypedNode is
|
||||
/// convertible into the respecitve types and then do the actual match
|
||||
/// on the actual node, or return false if it is not convertible.
|
||||
class DynTypedMatcher {
|
||||
public:
|
||||
virtual ~DynTypedMatcher() {}
|
||||
|
||||
/// \brief Returns true if the matcher matches the given \c DynNode.
|
||||
virtual bool matches(const ast_type_traits::DynTypedNode DynNode,
|
||||
ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const = 0;
|
||||
|
||||
/// \brief Returns a unique ID for the matcher.
|
||||
virtual uint64_t getID() const = 0;
|
||||
};
|
||||
|
||||
/// \brief Wrapper of a MatcherInterface<T> *that allows copying.
|
||||
///
|
||||
/// A Matcher<Base> can be used anywhere a Matcher<Derived> is
|
||||
@ -196,12 +252,32 @@ class SingleNodeMatcherInterface : public MatcherInterface<T> {
|
||||
/// operator rather than a type hierarchy to be able to templatize the
|
||||
/// type hierarchy instead of spelling it out.
|
||||
template <typename T>
|
||||
class Matcher {
|
||||
class Matcher : public DynTypedMatcher {
|
||||
public:
|
||||
/// \brief Takes ownership of the provided implementation pointer.
|
||||
explicit Matcher(MatcherInterface<T> *Implementation)
|
||||
: Implementation(Implementation) {}
|
||||
|
||||
/// \brief Implicitly converts \c Other to a Matcher<T>.
|
||||
///
|
||||
/// Requires \c T to be derived from \c From.
|
||||
template <typename From>
|
||||
Matcher(const Matcher<From> &Other,
|
||||
typename llvm::enable_if_c<
|
||||
llvm::is_base_of<From, T>::value &&
|
||||
!llvm::is_same<From, T>::value >::type* = 0)
|
||||
: Implementation(new ImplicitCastMatcher<From>(Other)) {}
|
||||
|
||||
/// \brief Implicitly converts \c Matcher<Type> to \c Matcher<QualType>.
|
||||
///
|
||||
/// The resulting matcher is not strict, i.e. ignores qualifiers.
|
||||
template <typename TypeT>
|
||||
Matcher(const Matcher<TypeT> &Other,
|
||||
typename llvm::enable_if_c<
|
||||
llvm::is_same<T, QualType>::value &&
|
||||
llvm::is_same<TypeT, Type>::value >::type* = 0)
|
||||
: Implementation(new TypeToQualType<TypeT>(Other)) {}
|
||||
|
||||
/// \brief Forwards the call to the underlying MatcherInterface<T> pointer.
|
||||
bool matches(const T &Node,
|
||||
ASTMatchFinder *Finder,
|
||||
@ -209,14 +285,6 @@ class Matcher {
|
||||
return Implementation->matches(Node, Finder, Builder);
|
||||
}
|
||||
|
||||
/// \brief Implicitly converts this object to a Matcher<Derived>.
|
||||
///
|
||||
/// Requires Derived to be derived from T.
|
||||
template <typename Derived>
|
||||
operator Matcher<Derived>() const {
|
||||
return Matcher<Derived>(new ImplicitCastMatcher<Derived>(*this));
|
||||
}
|
||||
|
||||
/// \brief Returns an ID that uniquely identifies the matcher.
|
||||
uint64_t getID() const {
|
||||
/// FIXME: Document the requirements this imposes on matcher
|
||||
@ -224,23 +292,55 @@ class Matcher {
|
||||
return reinterpret_cast<uint64_t>(Implementation.getPtr());
|
||||
}
|
||||
|
||||
/// \brief Returns whether the matcher matches on the given \c DynNode.
|
||||
virtual bool matches(const ast_type_traits::DynTypedNode DynNode,
|
||||
ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
const T *Node = DynNode.get<T>();
|
||||
if (!Node) return false;
|
||||
return matches(*Node, Finder, Builder);
|
||||
}
|
||||
|
||||
/// \brief Allows the conversion of a \c Matcher<Type> to a \c
|
||||
/// Matcher<QualType>.
|
||||
///
|
||||
/// Depending on the constructor argument, the matcher is either strict, i.e.
|
||||
/// does only matches in the absence of qualifiers, or not, i.e. simply
|
||||
/// ignores any qualifiers.
|
||||
template <typename TypeT>
|
||||
class TypeToQualType : public MatcherInterface<QualType> {
|
||||
public:
|
||||
TypeToQualType(const Matcher<TypeT> &InnerMatcher)
|
||||
: InnerMatcher(InnerMatcher) {}
|
||||
|
||||
virtual bool matches(const QualType &Node,
|
||||
ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
if (Node.isNull())
|
||||
return false;
|
||||
return InnerMatcher.matches(*Node, Finder, Builder);
|
||||
}
|
||||
private:
|
||||
const Matcher<TypeT> InnerMatcher;
|
||||
};
|
||||
|
||||
private:
|
||||
/// \brief Allows conversion from Matcher<T> to Matcher<Derived> if Derived
|
||||
/// is derived from T.
|
||||
template <typename Derived>
|
||||
class ImplicitCastMatcher : public MatcherInterface<Derived> {
|
||||
/// \brief Allows conversion from Matcher<Base> to Matcher<T> if T
|
||||
/// is derived from Base.
|
||||
template <typename Base>
|
||||
class ImplicitCastMatcher : public MatcherInterface<T> {
|
||||
public:
|
||||
explicit ImplicitCastMatcher(const Matcher<T> &From)
|
||||
explicit ImplicitCastMatcher(const Matcher<Base> &From)
|
||||
: From(From) {}
|
||||
|
||||
virtual bool matches(const Derived &Node,
|
||||
virtual bool matches(const T &Node,
|
||||
ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
return From.matches(Node, Finder, Builder);
|
||||
}
|
||||
|
||||
private:
|
||||
const Matcher<T> From;
|
||||
const Matcher<Base> From;
|
||||
};
|
||||
|
||||
llvm::IntrusiveRefCntPtr< MatcherInterface<T> > Implementation;
|
||||
@ -280,18 +380,14 @@ class HasDeclarationMatcher : public MatcherInterface<T> {
|
||||
/// FIXME: Add other ways to convert...
|
||||
if (Node.isNull())
|
||||
return false;
|
||||
CXXRecordDecl *NodeAsRecordDecl = Node->getAsCXXRecordDecl();
|
||||
return NodeAsRecordDecl != NULL &&
|
||||
InnerMatcher.matches(*NodeAsRecordDecl, Finder, Builder);
|
||||
return matchesDecl(Node->getAsCXXRecordDecl(), Finder, Builder);
|
||||
}
|
||||
|
||||
/// \brief Extracts the Decl of the callee of a CallExpr and returns whether
|
||||
/// the inner matcher matches on it.
|
||||
bool matchesSpecialized(const CallExpr &Node, ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
const Decl *NodeAsDecl = Node.getCalleeDecl();
|
||||
return NodeAsDecl != NULL &&
|
||||
InnerMatcher.matches(*NodeAsDecl, Finder, Builder);
|
||||
return matchesDecl(Node.getCalleeDecl(), Finder, Builder);
|
||||
}
|
||||
|
||||
/// \brief Extracts the Decl of the constructor call and returns whether the
|
||||
@ -299,96 +395,63 @@ class HasDeclarationMatcher : public MatcherInterface<T> {
|
||||
bool matchesSpecialized(const CXXConstructExpr &Node,
|
||||
ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
const Decl *NodeAsDecl = Node.getConstructor();
|
||||
return NodeAsDecl != NULL &&
|
||||
InnerMatcher.matches(*NodeAsDecl, Finder, Builder);
|
||||
return matchesDecl(Node.getConstructor(), Finder, Builder);
|
||||
}
|
||||
|
||||
/// \brief Extracts the \c ValueDecl a \c MemberExpr refers to and returns
|
||||
/// whether the inner matcher matches on it.
|
||||
bool matchesSpecialized(const MemberExpr &Node,
|
||||
ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
return matchesDecl(Node.getMemberDecl(), Finder, Builder);
|
||||
}
|
||||
|
||||
/// \brief Returns whether the inner matcher \c Node. Returns false if \c Node
|
||||
/// is \c NULL.
|
||||
bool matchesDecl(const Decl *Node,
|
||||
ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
return Node != NULL && InnerMatcher.matches(*Node, Finder, Builder);
|
||||
}
|
||||
|
||||
const Matcher<Decl> InnerMatcher;
|
||||
};
|
||||
|
||||
/// \brief IsBaseType<T>::value is true if T is a "base" type in the AST
|
||||
/// node class hierarchies (i.e. if T is Decl, Stmt, or QualType).
|
||||
/// node class hierarchies.
|
||||
template <typename T>
|
||||
struct IsBaseType {
|
||||
static const bool value =
|
||||
(llvm::is_same<T, Decl>::value ||
|
||||
llvm::is_same<T, Stmt>::value ||
|
||||
llvm::is_same<T, QualType>::value ||
|
||||
llvm::is_same<T, Type>::value ||
|
||||
llvm::is_same<T, TypeLoc>::value ||
|
||||
llvm::is_same<T, NestedNameSpecifier>::value ||
|
||||
llvm::is_same<T, NestedNameSpecifierLoc>::value ||
|
||||
llvm::is_same<T, CXXCtorInitializer>::value);
|
||||
};
|
||||
template <typename T>
|
||||
const bool IsBaseType<T>::value;
|
||||
|
||||
/// \brief Interface that can match any AST base node type and contains default
|
||||
/// implementations returning false.
|
||||
class UntypedBaseMatcher : public llvm::RefCountedBaseVPTR {
|
||||
public:
|
||||
virtual ~UntypedBaseMatcher() {}
|
||||
|
||||
virtual bool matches(const Decl &DeclNode, ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
return false;
|
||||
}
|
||||
virtual bool matches(const QualType &TypeNode, ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
return false;
|
||||
}
|
||||
virtual bool matches(const Stmt &StmtNode, ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
return false;
|
||||
}
|
||||
virtual bool matches(const CXXCtorInitializer &CtorInitNode,
|
||||
ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
/// \brief Returns a unique ID for the matcher.
|
||||
virtual uint64_t getID() const = 0;
|
||||
};
|
||||
|
||||
/// \brief An UntypedBaseMatcher that overwrites the Matches(...) method for
|
||||
/// node type T. T must be an AST base type.
|
||||
template <typename T>
|
||||
class TypedBaseMatcher : public UntypedBaseMatcher {
|
||||
TOOLING_COMPILE_ASSERT(IsBaseType<T>::value,
|
||||
typed_base_matcher_can_only_be_used_with_base_type);
|
||||
public:
|
||||
explicit TypedBaseMatcher(const Matcher<T> &InnerMatcher)
|
||||
: InnerMatcher(InnerMatcher) {}
|
||||
|
||||
using UntypedBaseMatcher::matches;
|
||||
/// \brief Implements UntypedBaseMatcher::Matches.
|
||||
///
|
||||
/// Since T is guaranteed to be a "base" AST node type, this method is
|
||||
/// guaranteed to override one of the matches() methods from
|
||||
/// UntypedBaseMatcher.
|
||||
virtual bool matches(const T &Node,
|
||||
ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
return InnerMatcher.matches(Node, Finder, Builder);
|
||||
}
|
||||
|
||||
/// \brief Implements UntypedBaseMatcher::getID.
|
||||
virtual uint64_t getID() const {
|
||||
return InnerMatcher.getID();
|
||||
}
|
||||
|
||||
private:
|
||||
Matcher<T> InnerMatcher;
|
||||
};
|
||||
|
||||
/// \brief Interface that allows matchers to traverse the AST.
|
||||
/// FIXME: Find a better name.
|
||||
///
|
||||
/// This provides two entry methods for each base node type in the AST:
|
||||
/// - matchesChildOf:
|
||||
/// This provides three entry methods for each base node type in the AST:
|
||||
/// - \c matchesChildOf:
|
||||
/// Matches a matcher on every child node of the given node. Returns true
|
||||
/// if at least one child node could be matched.
|
||||
/// - matchesDescendantOf:
|
||||
/// - \c matchesDescendantOf:
|
||||
/// Matches a matcher on all descendant nodes of the given node. Returns true
|
||||
/// if at least one descendant matched.
|
||||
/// - \c matchesAncestorOf:
|
||||
/// Matches a matcher on all ancestors of the given node. Returns true if
|
||||
/// at least one ancestor matched.
|
||||
///
|
||||
/// FIXME: Currently we only allow Stmt and Decl nodes to start a traversal.
|
||||
/// In the future, we wan to implement this for all nodes for which it makes
|
||||
/// sense. In the case of matchesAncestorOf, we'll want to implement it for
|
||||
/// all nodes, as all nodes have ancestors.
|
||||
class ASTMatchFinder {
|
||||
public:
|
||||
/// \brief Defines how we descend a level in the AST when we pass
|
||||
@ -408,6 +471,14 @@ class ASTMatchFinder {
|
||||
BK_All
|
||||
};
|
||||
|
||||
/// \brief Defines which ancestors are considered for a match.
|
||||
enum AncestorMatchMode {
|
||||
/// All ancestors.
|
||||
AMM_All,
|
||||
/// Direct parent only.
|
||||
AMM_ParentOnly
|
||||
};
|
||||
|
||||
virtual ~ASTMatchFinder() {}
|
||||
|
||||
/// \brief Returns true if the given class is directly or indirectly derived
|
||||
@ -418,26 +489,70 @@ class ASTMatchFinder {
|
||||
const Matcher<NamedDecl> &Base,
|
||||
BoundNodesTreeBuilder *Builder) = 0;
|
||||
|
||||
// FIXME: Implement for other base nodes.
|
||||
virtual bool matchesChildOf(const Decl &DeclNode,
|
||||
const UntypedBaseMatcher &BaseMatcher,
|
||||
BoundNodesTreeBuilder *Builder,
|
||||
TraversalKind Traverse,
|
||||
BindKind Bind) = 0;
|
||||
virtual bool matchesChildOf(const Stmt &StmtNode,
|
||||
const UntypedBaseMatcher &BaseMatcher,
|
||||
template <typename T>
|
||||
bool matchesChildOf(const T &Node,
|
||||
const DynTypedMatcher &Matcher,
|
||||
BoundNodesTreeBuilder *Builder,
|
||||
TraversalKind Traverse,
|
||||
BindKind Bind) {
|
||||
TOOLING_COMPILE_ASSERT(
|
||||
(llvm::is_base_of<Decl, T>::value ||
|
||||
llvm::is_base_of<Stmt, T>::value ||
|
||||
llvm::is_base_of<NestedNameSpecifier, T>::value ||
|
||||
llvm::is_base_of<NestedNameSpecifierLoc, T>::value ||
|
||||
llvm::is_base_of<TypeLoc, T>::value ||
|
||||
llvm::is_base_of<QualType, T>::value),
|
||||
unsupported_type_for_recursive_matching);
|
||||
return matchesChildOf(ast_type_traits::DynTypedNode::create(Node),
|
||||
Matcher, Builder, Traverse, Bind);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool matchesDescendantOf(const T &Node,
|
||||
const DynTypedMatcher &Matcher,
|
||||
BoundNodesTreeBuilder *Builder,
|
||||
BindKind Bind) {
|
||||
TOOLING_COMPILE_ASSERT(
|
||||
(llvm::is_base_of<Decl, T>::value ||
|
||||
llvm::is_base_of<Stmt, T>::value ||
|
||||
llvm::is_base_of<NestedNameSpecifier, T>::value ||
|
||||
llvm::is_base_of<NestedNameSpecifierLoc, T>::value ||
|
||||
llvm::is_base_of<TypeLoc, T>::value ||
|
||||
llvm::is_base_of<QualType, T>::value),
|
||||
unsupported_type_for_recursive_matching);
|
||||
return matchesDescendantOf(ast_type_traits::DynTypedNode::create(Node),
|
||||
Matcher, Builder, Bind);
|
||||
}
|
||||
|
||||
// FIXME: Implement support for BindKind.
|
||||
template <typename T>
|
||||
bool matchesAncestorOf(const T &Node,
|
||||
const DynTypedMatcher &Matcher,
|
||||
BoundNodesTreeBuilder *Builder,
|
||||
AncestorMatchMode MatchMode) {
|
||||
TOOLING_COMPILE_ASSERT((llvm::is_base_of<Decl, T>::value ||
|
||||
llvm::is_base_of<Stmt, T>::value),
|
||||
only_Decl_or_Stmt_allowed_for_recursive_matching);
|
||||
return matchesAncestorOf(ast_type_traits::DynTypedNode::create(Node),
|
||||
Matcher, Builder, MatchMode);
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual bool matchesChildOf(const ast_type_traits::DynTypedNode &Node,
|
||||
const DynTypedMatcher &Matcher,
|
||||
BoundNodesTreeBuilder *Builder,
|
||||
TraversalKind Traverse,
|
||||
BindKind Bind) = 0;
|
||||
|
||||
virtual bool matchesDescendantOf(const Decl &DeclNode,
|
||||
const UntypedBaseMatcher &BaseMatcher,
|
||||
BoundNodesTreeBuilder *Builder,
|
||||
BindKind Bind) = 0;
|
||||
virtual bool matchesDescendantOf(const Stmt &StmtNode,
|
||||
const UntypedBaseMatcher &BaseMatcher,
|
||||
virtual bool matchesDescendantOf(const ast_type_traits::DynTypedNode &Node,
|
||||
const DynTypedMatcher &Matcher,
|
||||
BoundNodesTreeBuilder *Builder,
|
||||
BindKind Bind) = 0;
|
||||
|
||||
virtual bool matchesAncestorOf(const ast_type_traits::DynTypedNode &Node,
|
||||
const DynTypedMatcher &Matcher,
|
||||
BoundNodesTreeBuilder *Builder,
|
||||
AncestorMatchMode MatchMode) = 0;
|
||||
};
|
||||
|
||||
/// \brief Converts a \c Matcher<T> to a matcher of desired type \c To by
|
||||
@ -606,9 +721,6 @@ class BindableMatcher : public Matcher<T> {
|
||||
/// The returned matcher is equivalent to this matcher, but will
|
||||
/// bind the matched node on a match.
|
||||
Matcher<T> bind(StringRef ID) const {
|
||||
TOOLING_COMPILE_ASSERT((llvm::is_base_of<Stmt, T>::value ||
|
||||
llvm::is_base_of<Decl, T>::value),
|
||||
trying_to_bind_unsupported_node_type__only_decl_and_stmt_supported);
|
||||
return Matcher<T>(new IdMatcher<T>(ID, *this));
|
||||
}
|
||||
};
|
||||
@ -635,7 +747,7 @@ class HasMatcher : public MatcherInterface<T> {
|
||||
}
|
||||
|
||||
private:
|
||||
const TypedBaseMatcher<ChildT> ChildMatcher;
|
||||
const Matcher<ChildT> ChildMatcher;
|
||||
};
|
||||
|
||||
/// \brief Matches nodes of type T that have child nodes of type ChildT for
|
||||
@ -661,7 +773,7 @@ class ForEachMatcher : public MatcherInterface<T> {
|
||||
}
|
||||
|
||||
private:
|
||||
const TypedBaseMatcher<ChildT> ChildMatcher;
|
||||
const Matcher<ChildT> ChildMatcher;
|
||||
};
|
||||
|
||||
/// \brief Matches nodes of type T if the given Matcher<T> does not match.
|
||||
@ -733,6 +845,20 @@ class AnyOfMatcher : public MatcherInterface<T> {
|
||||
const Matcher<T> InnertMatcher2;
|
||||
};
|
||||
|
||||
/// \brief Creates a Matcher<T> that matches if all inner matchers match.
|
||||
template<typename T>
|
||||
BindableMatcher<T> makeAllOfComposite(
|
||||
ArrayRef<const Matcher<T> *> InnerMatchers) {
|
||||
if (InnerMatchers.empty())
|
||||
return BindableMatcher<T>(new TrueMatcher<T>);
|
||||
MatcherInterface<T> *InnerMatcher = new TrueMatcher<T>;
|
||||
for (int i = InnerMatchers.size() - 1; i >= 0; --i) {
|
||||
InnerMatcher = new AllOfMatcher<T, Matcher<T>, Matcher<T> >(
|
||||
*InnerMatchers[i], makeMatcher(InnerMatcher));
|
||||
}
|
||||
return BindableMatcher<T>(InnerMatcher);
|
||||
}
|
||||
|
||||
/// \brief Creates a Matcher<T> that matches if
|
||||
/// T is dyn_cast'able into InnerT and all inner matchers match.
|
||||
///
|
||||
@ -742,17 +868,8 @@ class AnyOfMatcher : public MatcherInterface<T> {
|
||||
template<typename T, typename InnerT>
|
||||
BindableMatcher<T> makeDynCastAllOfComposite(
|
||||
ArrayRef<const Matcher<InnerT> *> InnerMatchers) {
|
||||
if (InnerMatchers.empty()) {
|
||||
Matcher<InnerT> InnerMatcher = makeMatcher(new TrueMatcher<InnerT>);
|
||||
return BindableMatcher<T>(new DynCastMatcher<T, InnerT>(InnerMatcher));
|
||||
}
|
||||
Matcher<InnerT> InnerMatcher = *InnerMatchers.back();
|
||||
for (int i = InnerMatchers.size() - 2; i >= 0; --i) {
|
||||
InnerMatcher = makeMatcher(
|
||||
new AllOfMatcher<InnerT, Matcher<InnerT>, Matcher<InnerT> >(
|
||||
*InnerMatchers[i], InnerMatcher));
|
||||
}
|
||||
return BindableMatcher<T>(new DynCastMatcher<T, InnerT>(InnerMatcher));
|
||||
return BindableMatcher<T>(new DynCastMatcher<T, InnerT>(
|
||||
makeAllOfComposite(InnerMatchers)));
|
||||
}
|
||||
|
||||
/// \brief Matches nodes of type T that have at least one descendant node of
|
||||
@ -775,7 +892,53 @@ class HasDescendantMatcher : public MatcherInterface<T> {
|
||||
}
|
||||
|
||||
private:
|
||||
const TypedBaseMatcher<DescendantT> DescendantMatcher;
|
||||
const Matcher<DescendantT> DescendantMatcher;
|
||||
};
|
||||
|
||||
/// \brief Matches nodes of type \c T that have a parent node of type \c ParentT
|
||||
/// for which the given inner matcher matches.
|
||||
///
|
||||
/// \c ParentT must be an AST base type.
|
||||
template <typename T, typename ParentT>
|
||||
class HasParentMatcher : public MatcherInterface<T> {
|
||||
TOOLING_COMPILE_ASSERT(IsBaseType<ParentT>::value,
|
||||
has_parent_only_accepts_base_type_matcher);
|
||||
public:
|
||||
explicit HasParentMatcher(const Matcher<ParentT> &ParentMatcher)
|
||||
: ParentMatcher(ParentMatcher) {}
|
||||
|
||||
virtual bool matches(const T &Node,
|
||||
ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
return Finder->matchesAncestorOf(
|
||||
Node, ParentMatcher, Builder, ASTMatchFinder::AMM_ParentOnly);
|
||||
}
|
||||
|
||||
private:
|
||||
const Matcher<ParentT> ParentMatcher;
|
||||
};
|
||||
|
||||
/// \brief Matches nodes of type \c T that have at least one ancestor node of
|
||||
/// type \c AncestorT for which the given inner matcher matches.
|
||||
///
|
||||
/// \c AncestorT must be an AST base type.
|
||||
template <typename T, typename AncestorT>
|
||||
class HasAncestorMatcher : public MatcherInterface<T> {
|
||||
TOOLING_COMPILE_ASSERT(IsBaseType<AncestorT>::value,
|
||||
has_ancestor_only_accepts_base_type_matcher);
|
||||
public:
|
||||
explicit HasAncestorMatcher(const Matcher<AncestorT> &AncestorMatcher)
|
||||
: AncestorMatcher(AncestorMatcher) {}
|
||||
|
||||
virtual bool matches(const T &Node,
|
||||
ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
return Finder->matchesAncestorOf(
|
||||
Node, AncestorMatcher, Builder, ASTMatchFinder::AMM_All);
|
||||
}
|
||||
|
||||
private:
|
||||
const Matcher<AncestorT> AncestorMatcher;
|
||||
};
|
||||
|
||||
/// \brief Matches nodes of type T that have at least one descendant node of
|
||||
@ -801,7 +964,7 @@ class ForEachDescendantMatcher : public MatcherInterface<T> {
|
||||
}
|
||||
|
||||
private:
|
||||
const TypedBaseMatcher<DescendantT> DescendantMatcher;
|
||||
const Matcher<DescendantT> DescendantMatcher;
|
||||
};
|
||||
|
||||
/// \brief Matches on nodes that have a getValue() method if getValue() equals
|
||||
@ -858,6 +1021,22 @@ class IsTemplateInstantiationMatcher : public MatcherInterface<T> {
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief Matches on explicit template specializations for FunctionDecl,
|
||||
/// VarDecl or CXXRecordDecl nodes.
|
||||
template <typename T>
|
||||
class IsExplicitTemplateSpecializationMatcher : public MatcherInterface<T> {
|
||||
TOOLING_COMPILE_ASSERT((llvm::is_base_of<FunctionDecl, T>::value) ||
|
||||
(llvm::is_base_of<VarDecl, T>::value) ||
|
||||
(llvm::is_base_of<CXXRecordDecl, T>::value),
|
||||
requires_getTemplateSpecializationKind_method);
|
||||
public:
|
||||
virtual bool matches(const T& Node,
|
||||
ASTMatchFinder* Finder,
|
||||
BoundNodesTreeBuilder* Builder) const {
|
||||
return (Node.getTemplateSpecializationKind() == TSK_ExplicitSpecialization);
|
||||
}
|
||||
};
|
||||
|
||||
class IsArrowMatcher : public SingleNodeMatcherInterface<MemberExpr> {
|
||||
public:
|
||||
virtual bool matchesNode(const MemberExpr &Node) const {
|
||||
@ -894,6 +1073,166 @@ class VariadicDynCastAllOfMatcher
|
||||
VariadicDynCastAllOfMatcher() {}
|
||||
};
|
||||
|
||||
/// \brief A \c VariadicAllOfMatcher<T> object is a variadic functor that takes
|
||||
/// a number of \c Matcher<T> and returns a \c Matcher<T> that matches \c T
|
||||
/// nodes that are matched by all of the given matchers.
|
||||
///
|
||||
/// For example:
|
||||
/// const VariadicAllOfMatcher<NestedNameSpecifier> nestedNameSpecifier;
|
||||
/// Creates a functor nestedNameSpecifier(...) that creates a
|
||||
/// \c Matcher<NestedNameSpecifier> given a variable number of arguments of type
|
||||
/// \c Matcher<NestedNameSpecifier>.
|
||||
/// The returned matcher matches if all given matchers match.
|
||||
template <typename T>
|
||||
class VariadicAllOfMatcher : public llvm::VariadicFunction<
|
||||
BindableMatcher<T>, Matcher<T>,
|
||||
makeAllOfComposite<T> > {
|
||||
public:
|
||||
VariadicAllOfMatcher() {}
|
||||
};
|
||||
|
||||
/// \brief Matches nodes of type \c TLoc for which the inner
|
||||
/// \c Matcher<T> matches.
|
||||
template <typename TLoc, typename T>
|
||||
class LocMatcher : public MatcherInterface<TLoc> {
|
||||
public:
|
||||
explicit LocMatcher(const Matcher<T> &InnerMatcher)
|
||||
: InnerMatcher(InnerMatcher) {}
|
||||
|
||||
virtual bool matches(const TLoc &Node,
|
||||
ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
if (!Node)
|
||||
return false;
|
||||
return InnerMatcher.matches(*extract(Node), Finder, Builder);
|
||||
}
|
||||
|
||||
private:
|
||||
const NestedNameSpecifier *extract(const NestedNameSpecifierLoc &Loc) const {
|
||||
return Loc.getNestedNameSpecifier();
|
||||
}
|
||||
|
||||
const Matcher<T> InnerMatcher;
|
||||
};
|
||||
|
||||
/// \brief Matches \c NestedNameSpecifiers with a prefix matching another
|
||||
/// \c Matcher<NestedNameSpecifier>.
|
||||
class NestedNameSpecifierPrefixMatcher
|
||||
: public MatcherInterface<NestedNameSpecifier> {
|
||||
public:
|
||||
explicit NestedNameSpecifierPrefixMatcher(
|
||||
const Matcher<NestedNameSpecifier> &InnerMatcher)
|
||||
: InnerMatcher(InnerMatcher) {}
|
||||
|
||||
virtual bool matches(const NestedNameSpecifier &Node,
|
||||
ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
NestedNameSpecifier *NextNode = Node.getPrefix();
|
||||
if (NextNode == NULL)
|
||||
return false;
|
||||
return InnerMatcher.matches(*NextNode, Finder, Builder);
|
||||
}
|
||||
|
||||
private:
|
||||
const Matcher<NestedNameSpecifier> InnerMatcher;
|
||||
};
|
||||
|
||||
/// \brief Matches \c NestedNameSpecifierLocs with a prefix matching another
|
||||
/// \c Matcher<NestedNameSpecifierLoc>.
|
||||
class NestedNameSpecifierLocPrefixMatcher
|
||||
: public MatcherInterface<NestedNameSpecifierLoc> {
|
||||
public:
|
||||
explicit NestedNameSpecifierLocPrefixMatcher(
|
||||
const Matcher<NestedNameSpecifierLoc> &InnerMatcher)
|
||||
: InnerMatcher(InnerMatcher) {}
|
||||
|
||||
virtual bool matches(const NestedNameSpecifierLoc &Node,
|
||||
ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
NestedNameSpecifierLoc NextNode = Node.getPrefix();
|
||||
if (!NextNode)
|
||||
return false;
|
||||
return InnerMatcher.matches(NextNode, Finder, Builder);
|
||||
}
|
||||
|
||||
private:
|
||||
const Matcher<NestedNameSpecifierLoc> InnerMatcher;
|
||||
};
|
||||
|
||||
/// \brief Matches \c TypeLocs based on an inner matcher matching a certain
|
||||
/// \c QualType.
|
||||
///
|
||||
/// Used to implement the \c loc() matcher.
|
||||
class TypeLocTypeMatcher : public MatcherInterface<TypeLoc> {
|
||||
public:
|
||||
explicit TypeLocTypeMatcher(const Matcher<QualType> &InnerMatcher)
|
||||
: InnerMatcher(InnerMatcher) {}
|
||||
|
||||
virtual bool matches(const TypeLoc &Node,
|
||||
ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
if (!Node)
|
||||
return false;
|
||||
return InnerMatcher.matches(Node.getType(), Finder, Builder);
|
||||
}
|
||||
|
||||
private:
|
||||
const Matcher<QualType> InnerMatcher;
|
||||
};
|
||||
|
||||
/// \brief Matches nodes of type \c T for which the inner matcher matches on a
|
||||
/// another node of type \c T that can be reached using a given traverse
|
||||
/// function.
|
||||
template <typename T>
|
||||
class TypeTraverseMatcher : public MatcherInterface<T> {
|
||||
public:
|
||||
explicit TypeTraverseMatcher(const Matcher<QualType> &InnerMatcher,
|
||||
QualType (T::*TraverseFunction)() const)
|
||||
: InnerMatcher(InnerMatcher), TraverseFunction(TraverseFunction) {}
|
||||
|
||||
virtual bool matches(const T &Node,
|
||||
ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
QualType NextNode = (Node.*TraverseFunction)();
|
||||
if (NextNode.isNull())
|
||||
return false;
|
||||
return InnerMatcher.matches(NextNode, Finder, Builder);
|
||||
}
|
||||
|
||||
private:
|
||||
const Matcher<QualType> InnerMatcher;
|
||||
QualType (T::*TraverseFunction)() const;
|
||||
};
|
||||
|
||||
/// \brief Matches nodes of type \c T in a ..Loc hierarchy, for which the inner
|
||||
/// matcher matches on a another node of type \c T that can be reached using a
|
||||
/// given traverse function.
|
||||
template <typename T>
|
||||
class TypeLocTraverseMatcher : public MatcherInterface<T> {
|
||||
public:
|
||||
explicit TypeLocTraverseMatcher(const Matcher<TypeLoc> &InnerMatcher,
|
||||
TypeLoc (T::*TraverseFunction)() const)
|
||||
: InnerMatcher(InnerMatcher), TraverseFunction(TraverseFunction) {}
|
||||
|
||||
virtual bool matches(const T &Node,
|
||||
ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
TypeLoc NextNode = (Node.*TraverseFunction)();
|
||||
if (!NextNode)
|
||||
return false;
|
||||
return InnerMatcher.matches(NextNode, Finder, Builder);
|
||||
}
|
||||
|
||||
private:
|
||||
const Matcher<TypeLoc> InnerMatcher;
|
||||
TypeLoc (T::*TraverseFunction)() const;
|
||||
};
|
||||
|
||||
template <typename T, typename InnerT>
|
||||
T makeTypeAllOfComposite(ArrayRef<const Matcher<InnerT> *> InnerMatchers) {
|
||||
return T(makeAllOfComposite<InnerT>(InnerMatchers));
|
||||
}
|
||||
|
||||
} // end namespace internal
|
||||
} // end namespace ast_matchers
|
||||
} // end namespace clang
|
||||
|
@ -221,4 +221,69 @@
|
||||
const NodeType &Node, ASTMatchFinder *Finder, \
|
||||
BoundNodesTreeBuilder *Builder) const
|
||||
|
||||
/// \brief Creates a variadic matcher for both a specific \c Type as well as
|
||||
/// the corresponding \c TypeLoc.
|
||||
#define AST_TYPE_MATCHER(NodeType, MatcherName) \
|
||||
const internal::VariadicDynCastAllOfMatcher<Type, NodeType> MatcherName; \
|
||||
const internal::VariadicDynCastAllOfMatcher<TypeLoc, \
|
||||
NodeType##Loc> MatcherName##Loc
|
||||
|
||||
/// \brief AST_TYPE_TRAVERSE_MATCHER(MatcherName, FunctionName) defines
|
||||
/// the matcher \c MatcherName that can be used to traverse from one \c Type
|
||||
/// to another.
|
||||
///
|
||||
/// For a specific \c SpecificType, the traversal is done using
|
||||
/// \c SpecificType::FunctionName. The existance of such a function determines
|
||||
/// whether a corresponding matcher can be used on \c SpecificType.
|
||||
#define AST_TYPE_TRAVERSE_MATCHER(MatcherName, FunctionName) \
|
||||
class Polymorphic##MatcherName##TypeMatcher { \
|
||||
public: \
|
||||
Polymorphic##MatcherName##TypeMatcher( \
|
||||
const internal::Matcher<QualType> &InnerMatcher) \
|
||||
: InnerMatcher(InnerMatcher) {} \
|
||||
template <typename T> operator internal::Matcher<T>() { \
|
||||
return internal::Matcher<T>(new internal::TypeTraverseMatcher<T>( \
|
||||
InnerMatcher, &T::FunctionName)); \
|
||||
} \
|
||||
private: \
|
||||
const internal::Matcher<QualType> InnerMatcher; \
|
||||
}; \
|
||||
class Variadic##MatcherName##TypeTraverseMatcher \
|
||||
: public llvm::VariadicFunction< \
|
||||
Polymorphic##MatcherName##TypeMatcher, \
|
||||
internal::Matcher<QualType>, \
|
||||
internal::makeTypeAllOfComposite< \
|
||||
Polymorphic##MatcherName##TypeMatcher, QualType> > { \
|
||||
public: \
|
||||
Variadic##MatcherName##TypeTraverseMatcher() {} \
|
||||
}; \
|
||||
const Variadic##MatcherName##TypeTraverseMatcher MatcherName
|
||||
|
||||
/// \brief AST_TYPELOC_TRAVERSE_MATCHER(MatcherName, FunctionName) works
|
||||
/// identical to \c AST_TYPE_TRAVERSE_MATCHER but operates on \c TypeLocs.
|
||||
#define AST_TYPELOC_TRAVERSE_MATCHER(MatcherName, FunctionName) \
|
||||
class Polymorphic##MatcherName##TypeLocMatcher { \
|
||||
public: \
|
||||
Polymorphic##MatcherName##TypeLocMatcher( \
|
||||
const internal::Matcher<TypeLoc> &InnerMatcher) \
|
||||
: InnerMatcher(InnerMatcher) {} \
|
||||
template <typename T> operator internal::Matcher<T>() { \
|
||||
return internal::Matcher<T>(new internal::TypeLocTraverseMatcher<T>( \
|
||||
InnerMatcher, &T::FunctionName##Loc)); \
|
||||
} \
|
||||
private: \
|
||||
const internal::Matcher<TypeLoc> InnerMatcher; \
|
||||
}; \
|
||||
class Variadic##MatcherName##TypeLocTraverseMatcher \
|
||||
: public llvm::VariadicFunction< \
|
||||
Polymorphic##MatcherName##TypeLocMatcher, \
|
||||
internal::Matcher<TypeLoc>, \
|
||||
internal::makeTypeAllOfComposite< \
|
||||
Polymorphic##MatcherName##TypeLocMatcher, TypeLoc> > { \
|
||||
public: \
|
||||
Variadic##MatcherName##TypeLocTraverseMatcher() {} \
|
||||
}; \
|
||||
const Variadic##MatcherName##TypeLocTraverseMatcher MatcherName##Loc; \
|
||||
AST_TYPE_TRAVERSE_MATCHER(MatcherName, FunctionName##Type)
|
||||
|
||||
#endif // LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_MACROS_H
|
||||
|
209
include/clang/ASTMatchers/ASTTypeTraits.h
Normal file
209
include/clang/ASTMatchers/ASTTypeTraits.h
Normal file
@ -0,0 +1,209 @@
|
||||
//===--- ASTMatchersTypeTraits.h --------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Provides a dynamically typed node container that can be used to store
|
||||
// an AST base node at runtime in the same storage in a type safe way.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_MATCHERS_AST_TYPE_TRAITS_H
|
||||
#define LLVM_CLANG_AST_MATCHERS_AST_TYPE_TRAITS_H
|
||||
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/Stmt.h"
|
||||
#include "llvm/Support/AlignOf.h"
|
||||
|
||||
namespace clang {
|
||||
namespace ast_type_traits {
|
||||
|
||||
/// \brief A dynamically typed AST node container.
|
||||
///
|
||||
/// Stores an AST node in a type safe way. This allows writing code that
|
||||
/// works with different kinds of AST nodes, despite the fact that they don't
|
||||
/// have a common base class.
|
||||
///
|
||||
/// Use \c create(Node) to create a \c DynTypedNode from an AST node,
|
||||
/// and \c get<T>() to retrieve the node as type T if the types match.
|
||||
///
|
||||
/// See \c NodeTypeTag for which node base types are currently supported;
|
||||
/// You can create DynTypedNodes for all nodes in the inheritance hierarchy of
|
||||
/// the supported base types.
|
||||
class DynTypedNode {
|
||||
public:
|
||||
/// \brief Creates a \c DynTypedNode from \c Node.
|
||||
template <typename T>
|
||||
static DynTypedNode create(const T &Node) {
|
||||
return BaseConverter<T>::create(Node);
|
||||
}
|
||||
|
||||
/// \brief Retrieve the stored node as type \c T.
|
||||
///
|
||||
/// Returns NULL if the stored node does not have a type that is
|
||||
/// convertible to \c T.
|
||||
///
|
||||
/// For types that have identity via their pointer in the AST
|
||||
/// (like \c Stmt and \c Decl) the returned pointer points to the
|
||||
/// referenced AST node.
|
||||
/// For other types (like \c QualType) the value is stored directly
|
||||
/// in the \c DynTypedNode, and the returned pointer points at
|
||||
/// the storage inside DynTypedNode. For those nodes, do not
|
||||
/// use the pointer outside the scope of the DynTypedNode.
|
||||
template <typename T>
|
||||
const T *get() const {
|
||||
return BaseConverter<T>::get(Tag, Storage.buffer);
|
||||
}
|
||||
|
||||
/// \brief Returns a pointer that identifies the stored AST node.
|
||||
///
|
||||
/// Note that this is not supported by all AST nodes. For AST nodes
|
||||
/// that don't have a pointer-defined identity inside the AST, this
|
||||
/// method returns NULL.
|
||||
const void *getMemoizationData() const;
|
||||
|
||||
private:
|
||||
/// \brief Takes care of converting from and to \c T.
|
||||
template <typename T, typename EnablerT = void> struct BaseConverter;
|
||||
|
||||
/// \brief Supported base node types.
|
||||
enum NodeTypeTag {
|
||||
NT_Decl,
|
||||
NT_Stmt,
|
||||
NT_NestedNameSpecifier,
|
||||
NT_NestedNameSpecifierLoc,
|
||||
NT_QualType,
|
||||
NT_Type,
|
||||
NT_TypeLoc
|
||||
} Tag;
|
||||
|
||||
/// \brief Stores the data of the node.
|
||||
///
|
||||
/// Note that we can store \c Decls and \c Stmts by pointer as they are
|
||||
/// guaranteed to be unique pointers pointing to dedicated storage in the
|
||||
/// AST. \c QualTypes on the other hand do not have storage or unique
|
||||
/// pointers and thus need to be stored by value.
|
||||
llvm::AlignedCharArrayUnion<Decl*, QualType, TypeLoc, NestedNameSpecifierLoc>
|
||||
Storage;
|
||||
};
|
||||
|
||||
// FIXME: Pull out abstraction for the following.
|
||||
template<typename T> struct DynTypedNode::BaseConverter<T,
|
||||
typename llvm::enable_if<llvm::is_base_of<Decl, T> >::type> {
|
||||
static const T *get(NodeTypeTag Tag, const char Storage[]) {
|
||||
if (Tag == NT_Decl)
|
||||
return dyn_cast<T>(*reinterpret_cast<Decl*const*>(Storage));
|
||||
return NULL;
|
||||
}
|
||||
static DynTypedNode create(const Decl &Node) {
|
||||
DynTypedNode Result;
|
||||
Result.Tag = NT_Decl;
|
||||
new (Result.Storage.buffer) const Decl*(&Node);
|
||||
return Result;
|
||||
}
|
||||
};
|
||||
template<typename T> struct DynTypedNode::BaseConverter<T,
|
||||
typename llvm::enable_if<llvm::is_base_of<Stmt, T> >::type> {
|
||||
static const T *get(NodeTypeTag Tag, const char Storage[]) {
|
||||
if (Tag == NT_Stmt)
|
||||
return dyn_cast<T>(*reinterpret_cast<Stmt*const*>(Storage));
|
||||
return NULL;
|
||||
}
|
||||
static DynTypedNode create(const Stmt &Node) {
|
||||
DynTypedNode Result;
|
||||
Result.Tag = NT_Stmt;
|
||||
new (Result.Storage.buffer) const Stmt*(&Node);
|
||||
return Result;
|
||||
}
|
||||
};
|
||||
template<typename T> struct DynTypedNode::BaseConverter<T,
|
||||
typename llvm::enable_if<llvm::is_base_of<Type, T> >::type> {
|
||||
static const T *get(NodeTypeTag Tag, const char Storage[]) {
|
||||
if (Tag == NT_Type)
|
||||
return dyn_cast<T>(*reinterpret_cast<Type*const*>(Storage));
|
||||
return NULL;
|
||||
}
|
||||
static DynTypedNode create(const Type &Node) {
|
||||
DynTypedNode Result;
|
||||
Result.Tag = NT_Type;
|
||||
new (Result.Storage.buffer) const Type*(&Node);
|
||||
return Result;
|
||||
}
|
||||
};
|
||||
template<> struct DynTypedNode::BaseConverter<NestedNameSpecifier, void> {
|
||||
static const NestedNameSpecifier *get(NodeTypeTag Tag, const char Storage[]) {
|
||||
if (Tag == NT_NestedNameSpecifier)
|
||||
return *reinterpret_cast<NestedNameSpecifier*const*>(Storage);
|
||||
return NULL;
|
||||
}
|
||||
static DynTypedNode create(const NestedNameSpecifier &Node) {
|
||||
DynTypedNode Result;
|
||||
Result.Tag = NT_NestedNameSpecifier;
|
||||
new (Result.Storage.buffer) const NestedNameSpecifier*(&Node);
|
||||
return Result;
|
||||
}
|
||||
};
|
||||
template<> struct DynTypedNode::BaseConverter<NestedNameSpecifierLoc, void> {
|
||||
static const NestedNameSpecifierLoc *get(NodeTypeTag Tag,
|
||||
const char Storage[]) {
|
||||
if (Tag == NT_NestedNameSpecifierLoc)
|
||||
return reinterpret_cast<const NestedNameSpecifierLoc*>(Storage);
|
||||
return NULL;
|
||||
}
|
||||
static DynTypedNode create(const NestedNameSpecifierLoc &Node) {
|
||||
DynTypedNode Result;
|
||||
Result.Tag = NT_NestedNameSpecifierLoc;
|
||||
new (Result.Storage.buffer) NestedNameSpecifierLoc(Node);
|
||||
return Result;
|
||||
}
|
||||
};
|
||||
template<> struct DynTypedNode::BaseConverter<QualType, void> {
|
||||
static const QualType *get(NodeTypeTag Tag, const char Storage[]) {
|
||||
if (Tag == NT_QualType)
|
||||
return reinterpret_cast<const QualType*>(Storage);
|
||||
return NULL;
|
||||
}
|
||||
static DynTypedNode create(const QualType &Node) {
|
||||
DynTypedNode Result;
|
||||
Result.Tag = NT_QualType;
|
||||
new (Result.Storage.buffer) QualType(Node);
|
||||
return Result;
|
||||
}
|
||||
};
|
||||
template<> struct DynTypedNode::BaseConverter<TypeLoc, void> {
|
||||
static const TypeLoc *get(NodeTypeTag Tag, const char Storage[]) {
|
||||
if (Tag == NT_TypeLoc)
|
||||
return reinterpret_cast<const TypeLoc*>(Storage);
|
||||
return NULL;
|
||||
}
|
||||
static DynTypedNode create(const TypeLoc &Node) {
|
||||
DynTypedNode Result;
|
||||
Result.Tag = NT_TypeLoc;
|
||||
new (Result.Storage.buffer) TypeLoc(Node);
|
||||
return Result;
|
||||
}
|
||||
};
|
||||
// The only operation we allow on unsupported types is \c get.
|
||||
// This allows to conveniently use \c DynTypedNode when having an arbitrary
|
||||
// AST node that is not supported, but prevents misuse - a user cannot create
|
||||
// a DynTypedNode from arbitrary types.
|
||||
template <typename T, typename EnablerT> struct DynTypedNode::BaseConverter {
|
||||
static const T *get(NodeTypeTag Tag, const char Storage[]) { return NULL; }
|
||||
};
|
||||
|
||||
inline const void *DynTypedNode::getMemoizationData() const {
|
||||
switch (Tag) {
|
||||
case NT_Decl: return BaseConverter<Decl>::get(Tag, Storage.buffer);
|
||||
case NT_Stmt: return BaseConverter<Stmt>::get(Tag, Storage.buffer);
|
||||
default: return NULL;
|
||||
};
|
||||
}
|
||||
|
||||
} // end namespace ast_type_traits
|
||||
} // end namespace clang
|
||||
|
||||
#endif // LLVM_CLANG_AST_MATCHERS_AST_TYPE_TRAITS_H
|
@ -23,6 +23,8 @@
|
||||
|
||||
namespace clang {
|
||||
|
||||
class TargetInfo;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// Common components of both fprintf and fscanf format strings.
|
||||
namespace analyze_format_string {
|
||||
@ -115,11 +117,14 @@ class ConversionSpecifier {
|
||||
// C99 conversion specifiers.
|
||||
cArg,
|
||||
dArg,
|
||||
DArg, // Apple extension
|
||||
iArg,
|
||||
IntArgBeg = cArg, IntArgEnd = iArg,
|
||||
IntArgBeg = dArg, IntArgEnd = iArg,
|
||||
|
||||
oArg,
|
||||
OArg, // Apple extension
|
||||
uArg,
|
||||
UArg, // Apple extension
|
||||
xArg,
|
||||
XArg,
|
||||
UIntArgBeg = oArg, UIntArgEnd = XArg,
|
||||
@ -157,7 +162,7 @@ class ConversionSpecifier {
|
||||
ScanfConvBeg = ScanListArg, ScanfConvEnd = ScanListArg
|
||||
};
|
||||
|
||||
ConversionSpecifier(bool isPrintf)
|
||||
ConversionSpecifier(bool isPrintf = true)
|
||||
: IsPrintf(isPrintf), Position(0), EndScanList(0), kind(InvalidSpecifier) {}
|
||||
|
||||
ConversionSpecifier(bool isPrintf, const char *pos, Kind k)
|
||||
@ -189,10 +194,14 @@ class ConversionSpecifier {
|
||||
return EndScanList ? EndScanList - Position : 1;
|
||||
}
|
||||
|
||||
bool isIntArg() const { return kind >= IntArgBeg && kind <= IntArgEnd; }
|
||||
bool isUIntArg() const { return kind >= UIntArgBeg && kind <= UIntArgEnd; }
|
||||
bool isAnyIntArg() const { return kind >= IntArgBeg && kind <= UIntArgEnd; }
|
||||
const char *toString() const;
|
||||
|
||||
bool isPrintfKind() const { return IsPrintf; }
|
||||
|
||||
llvm::Optional<ConversionSpecifier> getStandardSpecifier() const;
|
||||
|
||||
protected:
|
||||
bool IsPrintf;
|
||||
@ -348,10 +357,12 @@ class FormatSpecifier {
|
||||
|
||||
bool usesPositionalArg() const { return UsesPositionalArg; }
|
||||
|
||||
bool hasValidLengthModifier() const;
|
||||
bool hasValidLengthModifier(const TargetInfo &Target) const;
|
||||
|
||||
bool hasStandardLengthModifier() const;
|
||||
|
||||
llvm::Optional<LengthModifier> getCorrectedLengthModifier() const;
|
||||
|
||||
bool hasStandardConversionSpecifier(const LangOptions &LangOpt) const;
|
||||
|
||||
bool hasStandardLengthConversionCombination() const;
|
||||
@ -378,7 +389,6 @@ class PrintfConversionSpecifier :
|
||||
: ConversionSpecifier(true, pos, k) {}
|
||||
|
||||
bool isObjCArg() const { return kind >= ObjCBeg && kind <= ObjCEnd; }
|
||||
bool isIntArg() const { return kind >= IntArgBeg && kind <= IntArgEnd; }
|
||||
bool isDoubleArg() const { return kind >= DoubleArgBeg &&
|
||||
kind <= DoubleArgEnd; }
|
||||
unsigned getLength() const {
|
||||
@ -623,10 +633,12 @@ class FormatStringHandler {
|
||||
};
|
||||
|
||||
bool ParsePrintfString(FormatStringHandler &H,
|
||||
const char *beg, const char *end, const LangOptions &LO);
|
||||
const char *beg, const char *end, const LangOptions &LO,
|
||||
const TargetInfo &Target);
|
||||
|
||||
bool ParseScanfString(FormatStringHandler &H,
|
||||
const char *beg, const char *end, const LangOptions &LO);
|
||||
const char *beg, const char *end, const LangOptions &LO,
|
||||
const TargetInfo &Target);
|
||||
|
||||
} // end analyze_format_string namespace
|
||||
} // end clang namespace
|
||||
|
@ -132,7 +132,8 @@ class ThreadSafetyHandler {
|
||||
/// \param Loc -- The location of the protected operation.
|
||||
virtual void handleMutexNotHeld(const NamedDecl *D,
|
||||
ProtectedOperationKind POK, Name LockName,
|
||||
LockKind LK, SourceLocation Loc) {}
|
||||
LockKind LK, SourceLocation Loc,
|
||||
Name *PossibleMatch=0) {}
|
||||
|
||||
/// Warn when a function is called while an excluded mutex is locked. For
|
||||
/// example, the mutex may be locked inside the function.
|
||||
|
@ -72,7 +72,7 @@ class AnalysisDeclContext {
|
||||
/// AnalysisDeclContext. This may be null.
|
||||
AnalysisDeclContextManager *Manager;
|
||||
|
||||
const Decl *D;
|
||||
const Decl * const D;
|
||||
|
||||
OwningPtr<CFG> cfg, completeCFG;
|
||||
OwningPtr<CFGStmtMap> cfgStmtMap;
|
||||
@ -81,9 +81,6 @@ class AnalysisDeclContext {
|
||||
CFG::BuildOptions::ForcedBlkExprs *forcedBlkExprs;
|
||||
|
||||
bool builtCFG, builtCompleteCFG;
|
||||
|
||||
OwningPtr<LiveVariables> liveness;
|
||||
OwningPtr<LiveVariables> relaxedLiveness;
|
||||
OwningPtr<ParentMap> PM;
|
||||
OwningPtr<PseudoConstantAnalysis> PCA;
|
||||
OwningPtr<CFGReverseBlockReachabilityAnalysis> CFA;
|
||||
@ -104,9 +101,15 @@ class AnalysisDeclContext {
|
||||
|
||||
~AnalysisDeclContext();
|
||||
|
||||
ASTContext &getASTContext() { return D->getASTContext(); }
|
||||
ASTContext &getASTContext() const { return D->getASTContext(); }
|
||||
const Decl *getDecl() const { return D; }
|
||||
|
||||
/// Return the AnalysisDeclContextManager (if any) that created
|
||||
/// this AnalysisDeclContext.
|
||||
AnalysisDeclContextManager *getManager() const {
|
||||
return Manager;
|
||||
}
|
||||
|
||||
/// Return the build options used to construct the CFG.
|
||||
CFG::BuildOptions &getCFGBuildOptions() {
|
||||
return cfgBuildOptions;
|
||||
@ -234,9 +237,10 @@ class LocationContext : public llvm::FoldingSetNode {
|
||||
|
||||
const StackFrameContext *getCurrentStackFrame() const;
|
||||
|
||||
virtual void Profile(llvm::FoldingSetNodeID &ID) = 0;
|
||||
/// Return true if the current LocationContext has no caller context.
|
||||
virtual bool inTopFrame() const;
|
||||
|
||||
static bool classof(const LocationContext*) { return true; }
|
||||
virtual void Profile(llvm::FoldingSetNodeID &ID) = 0;
|
||||
|
||||
public:
|
||||
static void ProfileCommon(llvm::FoldingSetNodeID &ID,
|
||||
@ -270,6 +274,9 @@ class StackFrameContext : public LocationContext {
|
||||
|
||||
const CFGBlock *getCallSiteBlock() const { return Block; }
|
||||
|
||||
/// Return true if the current LocationContext has no caller context.
|
||||
virtual bool inTopFrame() const { return getParent() == 0; }
|
||||
|
||||
unsigned getIndex() const { return Index; }
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID);
|
||||
@ -379,11 +386,17 @@ class AnalysisDeclContextManager {
|
||||
ContextMap Contexts;
|
||||
LocationContextManager LocContexts;
|
||||
CFG::BuildOptions cfgBuildOptions;
|
||||
|
||||
/// Flag to indicate whether or not bodies should be synthesized
|
||||
/// for well-known functions.
|
||||
bool SynthesizeBodies;
|
||||
|
||||
public:
|
||||
AnalysisDeclContextManager(bool useUnoptimizedCFG = false,
|
||||
bool addImplicitDtors = false,
|
||||
bool addInitializers = false);
|
||||
bool addImplicitDtors = false,
|
||||
bool addInitializers = false,
|
||||
bool addTemporaryDtors = false,
|
||||
bool synthesizeBodies = false);
|
||||
|
||||
~AnalysisDeclContextManager();
|
||||
|
||||
@ -396,6 +409,10 @@ class AnalysisDeclContextManager {
|
||||
CFG::BuildOptions &getCFGBuildOptions() {
|
||||
return cfgBuildOptions;
|
||||
}
|
||||
|
||||
/// Return true if faux bodies should be synthesized for well-known
|
||||
/// functions.
|
||||
bool synthesizeBodies() const { return SynthesizeBodies; }
|
||||
|
||||
const StackFrameContext *getStackFrame(AnalysisDeclContext *Ctx,
|
||||
LocationContext const *Parent,
|
||||
|
@ -88,8 +88,6 @@ class CFGElement {
|
||||
return static_cast<const ElemTy*>(this);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool classof(const CFGElement *E) { return true; }
|
||||
};
|
||||
|
||||
class CFGStmt : public CFGElement {
|
||||
@ -568,6 +566,7 @@ class CFG {
|
||||
bool AddEHEdges;
|
||||
bool AddInitializers;
|
||||
bool AddImplicitDtors;
|
||||
bool AddTemporaryDtors;
|
||||
|
||||
bool alwaysAdd(const Stmt *stmt) const {
|
||||
return alwaysAddMask[stmt->getStmtClass()];
|
||||
@ -587,7 +586,8 @@ class CFG {
|
||||
: forcedBlkExprs(0), PruneTriviallyFalseEdges(true)
|
||||
,AddEHEdges(false)
|
||||
,AddInitializers(false)
|
||||
,AddImplicitDtors(false) {}
|
||||
,AddImplicitDtors(false)
|
||||
,AddTemporaryDtors(false) {}
|
||||
};
|
||||
|
||||
/// \brief Provides a custom implementation of the iterator class to have the
|
||||
|
46
include/clang/Analysis/DomainSpecific/ObjCNoReturn.h
Normal file
46
include/clang/Analysis/DomainSpecific/ObjCNoReturn.h
Normal file
@ -0,0 +1,46 @@
|
||||
//= ObjCNoReturn.h - Handling of Cocoa APIs known not to return --*- C++ -*---//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements special handling of recognizing ObjC API hooks that
|
||||
// do not return but aren't marked as such in API headers.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSIS_DS_OBJCNORETURN
|
||||
#define LLVM_CLANG_ANALYSIS_DS_OBJCNORETURN
|
||||
|
||||
#include "clang/Basic/IdentifierTable.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
class ASTContext;
|
||||
class ObjCMessageExpr;
|
||||
|
||||
class ObjCNoReturn {
|
||||
/// Cached "raise" selector.
|
||||
Selector RaiseSel;
|
||||
|
||||
/// Cached identifier for "NSException".
|
||||
IdentifierInfo *NSExceptionII;
|
||||
|
||||
enum { NUM_RAISE_SELECTORS = 2 };
|
||||
|
||||
/// Cached set of selectors in NSException that are 'noreturn'.
|
||||
Selector NSExceptionInstanceRaiseSelectors[NUM_RAISE_SELECTORS];
|
||||
|
||||
public:
|
||||
ObjCNoReturn(ASTContext &C);
|
||||
|
||||
/// Return true if the given message expression is known to never
|
||||
/// return.
|
||||
bool isImplicitNoReturn(const ObjCMessageExpr *ME);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -140,8 +140,6 @@ class ProgramPoint {
|
||||
return ID.ComputeHash();
|
||||
}
|
||||
|
||||
static bool classof(const ProgramPoint*) { return true; }
|
||||
|
||||
bool operator==(const ProgramPoint & RHS) const {
|
||||
return Data1 == RHS.Data1 &&
|
||||
Data2 == RHS.Data2 &&
|
||||
@ -213,7 +211,9 @@ class StmtPoint : public ProgramPoint {
|
||||
public:
|
||||
StmtPoint(const Stmt *S, const void *p2, Kind k, const LocationContext *L,
|
||||
const ProgramPointTag *tag)
|
||||
: ProgramPoint(S, p2, k, L, tag) {}
|
||||
: ProgramPoint(S, p2, k, L, tag) {
|
||||
assert(S);
|
||||
}
|
||||
|
||||
const Stmt *getStmt() const { return (const Stmt*) getData1(); }
|
||||
|
||||
@ -461,6 +461,7 @@ class PostImplicitCall : public ImplicitCallPoint {
|
||||
};
|
||||
|
||||
/// Represents a point when we begin processing an inlined call.
|
||||
/// CallEnter uses the caller's location context.
|
||||
class CallEnter : public ProgramPoint {
|
||||
public:
|
||||
CallEnter(const Stmt *stmt, const StackFrameContext *calleeCtx,
|
||||
|
@ -190,7 +190,7 @@ def Availability : InheritableAttr {
|
||||
[{static llvm::StringRef getPrettyPlatformName(llvm::StringRef Platform) {
|
||||
return llvm::StringSwitch<llvm::StringRef>(Platform)
|
||||
.Case("ios", "iOS")
|
||||
.Case("macosx", "Mac OS X")
|
||||
.Case("macosx", "OS X")
|
||||
.Default(llvm::StringRef());
|
||||
} }];
|
||||
}
|
||||
@ -341,6 +341,11 @@ def Final : InheritableAttr {
|
||||
let SemaHandler = 0;
|
||||
}
|
||||
|
||||
def MinSize : InheritableAttr {
|
||||
let Spellings = [GNU<"minsize">];
|
||||
let Subjects = [Function];
|
||||
}
|
||||
|
||||
def Format : InheritableAttr {
|
||||
let Spellings = [GNU<"format">];
|
||||
let Args = [StringArgument<"Type">, IntArgument<"FormatIdx">,
|
||||
@ -528,6 +533,11 @@ def ObjCReturnsInnerPointer : Attr {
|
||||
let Subjects = [ObjCMethod];
|
||||
}
|
||||
|
||||
def ObjCRequiresSuper : InheritableAttr {
|
||||
let Spellings = [GNU<"objc_requires_super">];
|
||||
let Subjects = [ObjCMethod];
|
||||
}
|
||||
|
||||
def ObjCRootClass : Attr {
|
||||
let Spellings = [GNU<"objc_root_class">];
|
||||
let Subjects = [ObjCInterface];
|
||||
@ -556,6 +566,10 @@ def Packed : InheritableAttr {
|
||||
let Spellings = [GNU<"packed">];
|
||||
}
|
||||
|
||||
def PnaclCall : InheritableAttr {
|
||||
let Spellings = [GNU<"pnaclcall">];
|
||||
}
|
||||
|
||||
def Pcs : InheritableAttr {
|
||||
let Spellings = [GNU<"pcs">];
|
||||
let Args = [EnumArgument<"PCS", "PCSType",
|
||||
|
@ -41,6 +41,7 @@
|
||||
// J -> jmp_buf
|
||||
// SJ -> sigjmp_buf
|
||||
// K -> ucontext_t
|
||||
// p -> pid_t
|
||||
// . -> "...". This may only occur at the end of the function list.
|
||||
//
|
||||
// Types may be prefixed with the following modifiers:
|
||||
@ -388,6 +389,7 @@ BUILTIN(__builtin_popcountll, "iULLi", "nc")
|
||||
|
||||
// FIXME: These type signatures are not correct for targets with int != 32-bits
|
||||
// or with ULL != 64-bits.
|
||||
BUILTIN(__builtin_bswap16, "UsUs", "nc")
|
||||
BUILTIN(__builtin_bswap32, "UiUi", "nc")
|
||||
BUILTIN(__builtin_bswap64, "ULLiULLi", "nc")
|
||||
|
||||
@ -478,6 +480,7 @@ BUILTIN(__builtin_expect, "LiLiLi" , "nc")
|
||||
BUILTIN(__builtin_prefetch, "vvC*.", "nc")
|
||||
BUILTIN(__builtin_readcyclecounter, "ULLi", "n")
|
||||
BUILTIN(__builtin_trap, "v", "nr")
|
||||
BUILTIN(__builtin_debugtrap, "v", "n")
|
||||
BUILTIN(__builtin_unreachable, "v", "nr")
|
||||
BUILTIN(__builtin_shufflevector, "v." , "nc")
|
||||
BUILTIN(__builtin_alloca, "v*z" , "n")
|
||||
@ -735,7 +738,7 @@ LIBBUILTIN(strcasecmp, "icC*cC*", "f", "strings.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(strncasecmp, "icC*cC*z", "f", "strings.h", ALL_LANGUAGES)
|
||||
// POSIX unistd.h
|
||||
LIBBUILTIN(_exit, "vi", "fr", "unistd.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(vfork, "i", "fj", "unistd.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(vfork, "p", "fj", "unistd.h", ALL_LANGUAGES)
|
||||
// POSIX setjmp.h
|
||||
|
||||
// In some systems setjmp is a macro that expands to _setjmp. We undefine
|
||||
@ -826,9 +829,13 @@ LIBBUILTIN(atan2, "ddd", "fe", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(atan2l, "LdLdLd", "fe", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(atan2f, "fff", "fe", "math.h", ALL_LANGUAGES)
|
||||
|
||||
LIBBUILTIN(ceil, "dd", "fe", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(ceill, "LdLd", "fe", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(ceilf, "ff", "fe", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(ceil, "dd", "fc", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(ceill, "LdLd", "fc", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(ceilf, "ff", "fc", "math.h", ALL_LANGUAGES)
|
||||
|
||||
LIBBUILTIN(copysign, "ddd", "fc", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(copysignl, "LdLdLd", "fc", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(copysignf, "fff", "fc", "math.h", ALL_LANGUAGES)
|
||||
|
||||
LIBBUILTIN(cos, "dd", "fe", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(cosl, "LdLd", "fe", "math.h", ALL_LANGUAGES)
|
||||
@ -838,37 +845,53 @@ LIBBUILTIN(exp, "dd", "fe", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(expl, "LdLd", "fe", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(expf, "ff", "fe", "math.h", ALL_LANGUAGES)
|
||||
|
||||
LIBBUILTIN(fabs, "dd", "fe", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(fabsl, "LdLd", "fe", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(fabsf, "ff", "fe", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(exp2, "dd", "fe", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(exp2l, "LdLd", "fe", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(exp2f, "ff", "fe", "math.h", ALL_LANGUAGES)
|
||||
|
||||
LIBBUILTIN(floor, "dd", "fe", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(floorl, "LdLd", "fe", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(floorf, "ff", "fe", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(fabs, "dd", "fc", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(fabsl, "LdLd", "fc", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(fabsf, "ff", "fc", "math.h", ALL_LANGUAGES)
|
||||
|
||||
LIBBUILTIN(floor, "dd", "fc", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(floorl, "LdLd", "fc", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(floorf, "ff", "fc", "math.h", ALL_LANGUAGES)
|
||||
|
||||
LIBBUILTIN(fma, "dddd", "fc", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(fmal, "LdLdLdLd", "fc", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(fmaf, "ffff", "fc", "math.h", ALL_LANGUAGES)
|
||||
|
||||
LIBBUILTIN(fmax, "ddd", "fe", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(fmaxl, "LdLdLd", "fe", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(fmaxf, "fff", "fe", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(fmax, "ddd", "fc", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(fmaxl, "LdLdLd", "fc", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(fmaxf, "fff", "fc", "math.h", ALL_LANGUAGES)
|
||||
|
||||
LIBBUILTIN(fmin, "ddd", "fe", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(fminl, "LdLdLd", "fe", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(fminf, "fff", "fe", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(fmin, "ddd", "fc", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(fminl, "LdLdLd", "fc", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(fminf, "fff", "fc", "math.h", ALL_LANGUAGES)
|
||||
|
||||
LIBBUILTIN(log, "dd", "fe", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(logl, "LdLd", "fe", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(logf, "ff", "fe", "math.h", ALL_LANGUAGES)
|
||||
|
||||
LIBBUILTIN(log2, "dd", "fe", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(log2l, "LdLd", "fe", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(log2f, "ff", "fe", "math.h", ALL_LANGUAGES)
|
||||
|
||||
LIBBUILTIN(nearbyint, "dd", "fc", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(nearbyintl, "LdLd", "fc", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(nearbyintf, "ff", "fc", "math.h", ALL_LANGUAGES)
|
||||
|
||||
LIBBUILTIN(pow, "ddd", "fe", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(powl, "LdLdLd", "fe", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(powf, "fff", "fe", "math.h", ALL_LANGUAGES)
|
||||
|
||||
LIBBUILTIN(round, "dd", "fe", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(roundl, "LdLd", "fe", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(roundf, "ff", "fe", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(rint, "dd", "fc", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(rintl, "LdLd", "fc", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(rintf, "ff", "fc", "math.h", ALL_LANGUAGES)
|
||||
|
||||
LIBBUILTIN(round, "dd", "fc", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(roundl, "LdLd", "fc", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(roundf, "ff", "fc", "math.h", ALL_LANGUAGES)
|
||||
|
||||
LIBBUILTIN(sin, "dd", "fe", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(sinl, "LdLd", "fe", "math.h", ALL_LANGUAGES)
|
||||
@ -882,6 +905,10 @@ LIBBUILTIN(tan, "dd", "fe", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(tanl, "LdLd", "fe", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(tanf, "ff", "fe", "math.h", ALL_LANGUAGES)
|
||||
|
||||
LIBBUILTIN(trunc, "dd", "fc", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(truncl, "LdLd", "fc", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(truncf, "ff", "fc", "math.h", ALL_LANGUAGES)
|
||||
|
||||
// Blocks runtime Builtin math library functions
|
||||
LIBBUILTIN(_Block_object_assign, "vv*vC*iC", "f", "Blocks.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(_Block_object_dispose, "vvC*iC", "f", "Blocks.h", ALL_LANGUAGES)
|
||||
|
@ -14,6 +14,8 @@
|
||||
|
||||
// The format of this database matches clang/Basic/Builtins.def.
|
||||
|
||||
// MIPS DSP Rev 1
|
||||
|
||||
// Add/subtract with optional saturation
|
||||
BUILTIN(__builtin_mips_addu_qb, "V4ScV4ScV4Sc", "n")
|
||||
BUILTIN(__builtin_mips_addu_s_qb, "V4ScV4ScV4Sc", "n")
|
||||
@ -122,4 +124,65 @@ BUILTIN(__builtin_mips_lbux, "iv*i", "n")
|
||||
BUILTIN(__builtin_mips_lhx, "iv*i", "n")
|
||||
BUILTIN(__builtin_mips_lwx, "iv*i", "n")
|
||||
|
||||
// MIPS DSP Rev 2
|
||||
|
||||
BUILTIN(__builtin_mips_absq_s_qb, "V4ScV4Sc", "n")
|
||||
|
||||
BUILTIN(__builtin_mips_addqh_ph, "V2sV2sV2s", "nc")
|
||||
BUILTIN(__builtin_mips_addqh_r_ph, "V2sV2sV2s", "nc")
|
||||
BUILTIN(__builtin_mips_addqh_w, "iii", "nc")
|
||||
BUILTIN(__builtin_mips_addqh_r_w, "iii", "nc")
|
||||
|
||||
BUILTIN(__builtin_mips_addu_ph, "V2sV2sV2s", "n")
|
||||
BUILTIN(__builtin_mips_addu_s_ph, "V2sV2sV2s", "n")
|
||||
|
||||
BUILTIN(__builtin_mips_adduh_qb, "V4ScV4ScV4Sc", "nc")
|
||||
BUILTIN(__builtin_mips_adduh_r_qb, "V4ScV4ScV4Sc", "nc")
|
||||
|
||||
BUILTIN(__builtin_mips_append, "iiiIi", "nc")
|
||||
BUILTIN(__builtin_mips_balign, "iiiIi", "nc")
|
||||
|
||||
BUILTIN(__builtin_mips_cmpgdu_eq_qb, "iV4ScV4Sc", "n")
|
||||
BUILTIN(__builtin_mips_cmpgdu_lt_qb, "iV4ScV4Sc", "n")
|
||||
BUILTIN(__builtin_mips_cmpgdu_le_qb, "iV4ScV4Sc", "n")
|
||||
|
||||
BUILTIN(__builtin_mips_dpa_w_ph, "LLiLLiV2sV2s", "nc")
|
||||
BUILTIN(__builtin_mips_dps_w_ph, "LLiLLiV2sV2s", "nc")
|
||||
|
||||
BUILTIN(__builtin_mips_dpaqx_s_w_ph, "LLiLLiV2sV2s", "n")
|
||||
BUILTIN(__builtin_mips_dpaqx_sa_w_ph, "LLiLLiV2sV2s", "n")
|
||||
BUILTIN(__builtin_mips_dpax_w_ph, "LLiLLiV2sV2s", "nc")
|
||||
BUILTIN(__builtin_mips_dpsx_w_ph, "LLiLLiV2sV2s", "nc")
|
||||
BUILTIN(__builtin_mips_dpsqx_s_w_ph, "LLiLLiV2sV2s", "n")
|
||||
BUILTIN(__builtin_mips_dpsqx_sa_w_ph, "LLiLLiV2sV2s", "n")
|
||||
|
||||
BUILTIN(__builtin_mips_mul_ph, "V2sV2sV2s", "n")
|
||||
BUILTIN(__builtin_mips_mul_s_ph, "V2sV2sV2s", "n")
|
||||
|
||||
BUILTIN(__builtin_mips_mulq_rs_w, "iii", "n")
|
||||
BUILTIN(__builtin_mips_mulq_s_ph, "V2sV2sV2s", "n")
|
||||
BUILTIN(__builtin_mips_mulq_s_w, "iii", "n")
|
||||
BUILTIN(__builtin_mips_mulsa_w_ph, "LLiLLiV2sV2s", "nc")
|
||||
|
||||
BUILTIN(__builtin_mips_precr_qb_ph, "V4ScV2sV2s", "n")
|
||||
BUILTIN(__builtin_mips_precr_sra_ph_w, "V2siiIi", "nc")
|
||||
BUILTIN(__builtin_mips_precr_sra_r_ph_w, "V2siiIi", "nc")
|
||||
|
||||
BUILTIN(__builtin_mips_prepend, "iiiIi", "nc")
|
||||
|
||||
BUILTIN(__builtin_mips_shra_qb, "V4ScV4Sci", "nc")
|
||||
BUILTIN(__builtin_mips_shra_r_qb, "V4ScV4Sci", "nc")
|
||||
BUILTIN(__builtin_mips_shrl_ph, "V2sV2si", "nc")
|
||||
|
||||
BUILTIN(__builtin_mips_subqh_ph, "V2sV2sV2s", "nc")
|
||||
BUILTIN(__builtin_mips_subqh_r_ph, "V2sV2sV2s", "nc")
|
||||
BUILTIN(__builtin_mips_subqh_w, "iii", "nc")
|
||||
BUILTIN(__builtin_mips_subqh_r_w, "iii", "nc")
|
||||
|
||||
BUILTIN(__builtin_mips_subu_ph, "V2sV2sV2s", "n")
|
||||
BUILTIN(__builtin_mips_subu_s_ph, "V2sV2sV2s", "n")
|
||||
|
||||
BUILTIN(__builtin_mips_subuh_qb, "V4ScV4ScV4Sc", "nc")
|
||||
BUILTIN(__builtin_mips_subuh_r_qb, "V4ScV4ScV4Sc", "nc")
|
||||
|
||||
#undef BUILTIN
|
||||
|
@ -14,6 +14,7 @@
|
||||
|
||||
// The format of this database matches clang/Basic/Builtins.def.
|
||||
|
||||
// Builtins retained from previous PTX back-end
|
||||
BUILTIN(__builtin_ptx_read_tid_x, "i", "nc")
|
||||
BUILTIN(__builtin_ptx_read_tid_y, "i", "nc")
|
||||
BUILTIN(__builtin_ptx_read_tid_z, "i", "nc")
|
||||
@ -59,4 +60,249 @@ BUILTIN(__builtin_ptx_read_pm3, "i", "n")
|
||||
BUILTIN(__builtin_ptx_bar_sync, "vi", "n")
|
||||
|
||||
|
||||
// Builtins exposed as part of NVVM
|
||||
BUILTIN(__syncthreads, "v", "n")
|
||||
BUILTIN(__nvvm_bar0, "v", "n")
|
||||
BUILTIN(__nvvm_bar0_popc, "ii", "n")
|
||||
BUILTIN(__nvvm_bar0_and, "ii", "n")
|
||||
BUILTIN(__nvvm_bar0_or, "ii", "n")
|
||||
BUILTIN(__nvvm_membar_cta, "v", "n")
|
||||
BUILTIN(__nvvm_membar_gl, "v", "n")
|
||||
BUILTIN(__nvvm_membar_sys, "v", "n")
|
||||
BUILTIN(__nvvm_popc_i, "ii", "nc")
|
||||
BUILTIN(__nvvm_popc_ll, "LiLi", "nc")
|
||||
BUILTIN(__nvvm_prmt, "UiUiUiUi", "nc")
|
||||
BUILTIN(__nvvm_min_i, "iii", "nc")
|
||||
BUILTIN(__nvvm_min_ui, "UiUiUi", "nc")
|
||||
BUILTIN(__nvvm_min_ll, "LLiLLiLLi", "nc")
|
||||
BUILTIN(__nvvm_min_ull, "ULLiULLiULLi", "nc")
|
||||
BUILTIN(__nvvm_max_i, "iii", "nc")
|
||||
BUILTIN(__nvvm_max_ui, "UiUiUi", "nc")
|
||||
BUILTIN(__nvvm_max_ll, "LLiLLiLLi", "nc")
|
||||
BUILTIN(__nvvm_max_ull, "ULLiULLiULLi", "nc")
|
||||
BUILTIN(__nvvm_mulhi_i, "iii", "nc")
|
||||
BUILTIN(__nvvm_mulhi_ui, "UiUiUi", "nc")
|
||||
BUILTIN(__nvvm_mulhi_ll, "LLiLLiLLi", "nc")
|
||||
BUILTIN(__nvvm_mulhi_ull, "ULLiULLiULLi", "nc")
|
||||
BUILTIN(__nvvm_mul24_i, "iii", "nc")
|
||||
BUILTIN(__nvvm_mul24_ui, "UiUiUi", "nc")
|
||||
BUILTIN(__nvvm_brev32, "UiUi", "nc")
|
||||
BUILTIN(__nvvm_brev64, "ULLiULLi", "nc")
|
||||
BUILTIN(__nvvm_sad_i, "iiii", "nc")
|
||||
BUILTIN(__nvvm_sad_ui, "UiUiUiUi", "nc")
|
||||
BUILTIN(__nvvm_abs_i, "ii", "nc")
|
||||
BUILTIN(__nvvm_abs_ll, "LiLi", "nc")
|
||||
BUILTIN(__nvvm_floor_ftz_f, "ff", "nc")
|
||||
BUILTIN(__nvvm_floor_f, "ff", "nc")
|
||||
BUILTIN(__nvvm_floor_d, "dd", "nc")
|
||||
BUILTIN(__nvvm_fabs_ftz_f, "ff", "nc")
|
||||
BUILTIN(__nvvm_fabs_f, "ff", "nc")
|
||||
BUILTIN(__nvvm_fabs_d, "dd", "nc")
|
||||
BUILTIN(__nvvm_rcp_approx_ftz_d, "dd", "nc")
|
||||
BUILTIN(__nvvm_fmin_ftz_f, "fff", "nc")
|
||||
BUILTIN(__nvvm_fmin_f, "fff", "nc")
|
||||
BUILTIN(__nvvm_fmax_ftz_f, "fff", "nc")
|
||||
BUILTIN(__nvvm_fmax_f, "fff", "nc")
|
||||
BUILTIN(__nvvm_rsqrt_approx_ftz_f, "ff", "nc")
|
||||
BUILTIN(__nvvm_rsqrt_approx_f, "ff", "nc")
|
||||
BUILTIN(__nvvm_fmin_d, "ddd", "nc")
|
||||
BUILTIN(__nvvm_fmax_d, "ddd", "nc")
|
||||
BUILTIN(__nvvm_rsqrt_approx_d, "dd", "nc")
|
||||
BUILTIN(__nvvm_ceil_d, "dd", "nc")
|
||||
BUILTIN(__nvvm_trunc_d, "dd", "nc")
|
||||
BUILTIN(__nvvm_round_d, "dd", "nc")
|
||||
BUILTIN(__nvvm_ex2_approx_d, "dd", "nc")
|
||||
BUILTIN(__nvvm_lg2_approx_d, "dd", "nc")
|
||||
BUILTIN(__nvvm_round_ftz_f, "ff", "nc")
|
||||
BUILTIN(__nvvm_round_f, "ff", "nc")
|
||||
BUILTIN(__nvvm_ex2_approx_ftz_f, "ff", "nc")
|
||||
BUILTIN(__nvvm_ex2_approx_f, "ff", "nc")
|
||||
BUILTIN(__nvvm_lg2_approx_ftz_f, "ff", "nc")
|
||||
BUILTIN(__nvvm_lg2_approx_f, "ff", "nc")
|
||||
BUILTIN(__nvvm_sin_approx_ftz_f, "ff", "nc")
|
||||
BUILTIN(__nvvm_sin_approx_f, "ff", "nc")
|
||||
BUILTIN(__nvvm_cos_approx_ftz_f, "ff", "nc")
|
||||
BUILTIN(__nvvm_cos_approx_f, "ff", "nc")
|
||||
BUILTIN(__nvvm_trunc_ftz_f, "ff", "nc")
|
||||
BUILTIN(__nvvm_trunc_f, "ff", "nc")
|
||||
BUILTIN(__nvvm_ceil_ftz_f, "ff", "nc")
|
||||
BUILTIN(__nvvm_ceil_f, "ff", "nc")
|
||||
BUILTIN(__nvvm_saturate_d, "dd", "nc")
|
||||
BUILTIN(__nvvm_saturate_ftz_f, "ff", "nc")
|
||||
BUILTIN(__nvvm_saturate_f, "ff", "nc")
|
||||
BUILTIN(__nvvm_fma_rn_ftz_f, "ffff", "nc")
|
||||
BUILTIN(__nvvm_fma_rn_f, "ffff", "nc")
|
||||
BUILTIN(__nvvm_fma_rz_ftz_f, "ffff", "nc")
|
||||
BUILTIN(__nvvm_fma_rz_f, "ffff", "nc")
|
||||
BUILTIN(__nvvm_fma_rm_ftz_f, "ffff", "nc")
|
||||
BUILTIN(__nvvm_fma_rm_f, "ffff", "nc")
|
||||
BUILTIN(__nvvm_fma_rp_ftz_f, "ffff", "nc")
|
||||
BUILTIN(__nvvm_fma_rp_f, "ffff", "nc")
|
||||
BUILTIN(__nvvm_fma_rn_d, "dddd", "nc")
|
||||
BUILTIN(__nvvm_fma_rz_d, "dddd", "nc")
|
||||
BUILTIN(__nvvm_fma_rm_d, "dddd", "nc")
|
||||
BUILTIN(__nvvm_fma_rp_d, "dddd", "nc")
|
||||
BUILTIN(__nvvm_div_approx_ftz_f, "fff", "nc")
|
||||
BUILTIN(__nvvm_div_approx_f, "fff", "nc")
|
||||
BUILTIN(__nvvm_div_rn_ftz_f, "fff", "nc")
|
||||
BUILTIN(__nvvm_div_rn_f, "fff", "nc")
|
||||
BUILTIN(__nvvm_div_rz_ftz_f, "fff", "nc")
|
||||
BUILTIN(__nvvm_div_rz_f, "fff", "nc")
|
||||
BUILTIN(__nvvm_div_rm_ftz_f, "fff", "nc")
|
||||
BUILTIN(__nvvm_div_rm_f, "fff", "nc")
|
||||
BUILTIN(__nvvm_div_rp_ftz_f, "fff", "nc")
|
||||
BUILTIN(__nvvm_div_rp_f, "fff", "nc")
|
||||
BUILTIN(__nvvm_rcp_rn_ftz_f, "ff", "nc")
|
||||
BUILTIN(__nvvm_rcp_rn_f, "ff", "nc")
|
||||
BUILTIN(__nvvm_rcp_rz_ftz_f, "ff", "nc")
|
||||
BUILTIN(__nvvm_rcp_rz_f, "ff", "nc")
|
||||
BUILTIN(__nvvm_rcp_rm_ftz_f, "ff", "nc")
|
||||
BUILTIN(__nvvm_rcp_rm_f, "ff", "nc")
|
||||
BUILTIN(__nvvm_rcp_rp_ftz_f, "ff", "nc")
|
||||
BUILTIN(__nvvm_rcp_rp_f, "ff", "nc")
|
||||
BUILTIN(__nvvm_sqrt_rn_ftz_f, "ff", "nc")
|
||||
BUILTIN(__nvvm_sqrt_rn_f, "ff", "nc")
|
||||
BUILTIN(__nvvm_sqrt_rz_ftz_f, "ff", "nc")
|
||||
BUILTIN(__nvvm_sqrt_rz_f, "ff", "nc")
|
||||
BUILTIN(__nvvm_sqrt_rm_ftz_f, "ff", "nc")
|
||||
BUILTIN(__nvvm_sqrt_rm_f, "ff", "nc")
|
||||
BUILTIN(__nvvm_sqrt_rp_ftz_f, "ff", "nc")
|
||||
BUILTIN(__nvvm_sqrt_rp_f, "ff", "nc")
|
||||
BUILTIN(__nvvm_div_rn_d, "ddd", "nc")
|
||||
BUILTIN(__nvvm_div_rz_d, "ddd", "nc")
|
||||
BUILTIN(__nvvm_div_rm_d, "ddd", "nc")
|
||||
BUILTIN(__nvvm_div_rp_d, "ddd", "nc")
|
||||
BUILTIN(__nvvm_rcp_rn_d, "dd", "nc")
|
||||
BUILTIN(__nvvm_rcp_rz_d, "dd", "nc")
|
||||
BUILTIN(__nvvm_rcp_rm_d, "dd", "nc")
|
||||
BUILTIN(__nvvm_rcp_rp_d, "dd", "nc")
|
||||
BUILTIN(__nvvm_sqrt_rn_d, "dd", "nc")
|
||||
BUILTIN(__nvvm_sqrt_rz_d, "dd", "nc")
|
||||
BUILTIN(__nvvm_sqrt_rm_d, "dd", "nc")
|
||||
BUILTIN(__nvvm_sqrt_rp_d, "dd", "nc")
|
||||
BUILTIN(__nvvm_sqrt_approx_ftz_f, "ff", "nc")
|
||||
BUILTIN(__nvvm_sqrt_approx_f, "ff", "nc")
|
||||
BUILTIN(__nvvm_add_rn_d, "ddd", "nc")
|
||||
BUILTIN(__nvvm_add_rz_d, "ddd", "nc")
|
||||
BUILTIN(__nvvm_add_rm_d, "ddd", "nc")
|
||||
BUILTIN(__nvvm_add_rp_d, "ddd", "nc")
|
||||
BUILTIN(__nvvm_mul_rn_d, "ddd", "nc")
|
||||
BUILTIN(__nvvm_mul_rz_d, "ddd", "nc")
|
||||
BUILTIN(__nvvm_mul_rm_d, "ddd", "nc")
|
||||
BUILTIN(__nvvm_mul_rp_d, "ddd", "nc")
|
||||
BUILTIN(__nvvm_add_rm_ftz_f, "fff", "nc")
|
||||
BUILTIN(__nvvm_add_rm_f, "fff", "nc")
|
||||
BUILTIN(__nvvm_add_rp_ftz_f, "fff", "nc")
|
||||
BUILTIN(__nvvm_add_rp_f, "fff", "nc")
|
||||
BUILTIN(__nvvm_mul_rm_ftz_f, "fff", "nc")
|
||||
BUILTIN(__nvvm_mul_rm_f, "fff", "nc")
|
||||
BUILTIN(__nvvm_mul_rp_ftz_f, "fff", "nc")
|
||||
BUILTIN(__nvvm_mul_rp_f, "fff", "nc")
|
||||
BUILTIN(__nvvm_add_rn_ftz_f, "fff", "nc")
|
||||
BUILTIN(__nvvm_add_rn_f, "fff", "nc")
|
||||
BUILTIN(__nvvm_add_rz_ftz_f, "fff", "nc")
|
||||
BUILTIN(__nvvm_add_rz_f, "fff", "nc")
|
||||
BUILTIN(__nvvm_mul_rn_ftz_f, "fff", "nc")
|
||||
BUILTIN(__nvvm_mul_rn_f, "fff", "nc")
|
||||
BUILTIN(__nvvm_mul_rz_ftz_f, "fff", "nc")
|
||||
BUILTIN(__nvvm_mul_rz_f, "fff", "nc")
|
||||
BUILTIN(__nvvm_d2f_rn_ftz, "fd", "nc")
|
||||
BUILTIN(__nvvm_d2f_rn, "fd", "nc")
|
||||
BUILTIN(__nvvm_d2f_rz_ftz, "fd", "nc")
|
||||
BUILTIN(__nvvm_d2f_rz, "fd", "nc")
|
||||
BUILTIN(__nvvm_d2f_rm_ftz, "fd", "nc")
|
||||
BUILTIN(__nvvm_d2f_rm, "fd", "nc")
|
||||
BUILTIN(__nvvm_d2f_rp_ftz, "fd", "nc")
|
||||
BUILTIN(__nvvm_d2f_rp, "fd", "nc")
|
||||
BUILTIN(__nvvm_d2i_rn, "id", "nc")
|
||||
BUILTIN(__nvvm_d2i_rz, "id", "nc")
|
||||
BUILTIN(__nvvm_d2i_rm, "id", "nc")
|
||||
BUILTIN(__nvvm_d2i_rp, "id", "nc")
|
||||
BUILTIN(__nvvm_d2ui_rn, "Uid", "nc")
|
||||
BUILTIN(__nvvm_d2ui_rz, "Uid", "nc")
|
||||
BUILTIN(__nvvm_d2ui_rm, "Uid", "nc")
|
||||
BUILTIN(__nvvm_d2ui_rp, "Uid", "nc")
|
||||
BUILTIN(__nvvm_i2d_rn, "di", "nc")
|
||||
BUILTIN(__nvvm_i2d_rz, "di", "nc")
|
||||
BUILTIN(__nvvm_i2d_rm, "di", "nc")
|
||||
BUILTIN(__nvvm_i2d_rp, "di", "nc")
|
||||
BUILTIN(__nvvm_ui2d_rn, "dUi", "nc")
|
||||
BUILTIN(__nvvm_ui2d_rz, "dUi", "nc")
|
||||
BUILTIN(__nvvm_ui2d_rm, "dUi", "nc")
|
||||
BUILTIN(__nvvm_ui2d_rp, "dUi", "nc")
|
||||
BUILTIN(__nvvm_f2i_rn_ftz, "if", "nc")
|
||||
BUILTIN(__nvvm_f2i_rn, "if", "nc")
|
||||
BUILTIN(__nvvm_f2i_rz_ftz, "if", "nc")
|
||||
BUILTIN(__nvvm_f2i_rz, "if", "nc")
|
||||
BUILTIN(__nvvm_f2i_rm_ftz, "if", "nc")
|
||||
BUILTIN(__nvvm_f2i_rm, "if", "nc")
|
||||
BUILTIN(__nvvm_f2i_rp_ftz, "if", "nc")
|
||||
BUILTIN(__nvvm_f2i_rp, "if", "nc")
|
||||
BUILTIN(__nvvm_f2ui_rn_ftz, "Uif", "nc")
|
||||
BUILTIN(__nvvm_f2ui_rn, "Uif", "nc")
|
||||
BUILTIN(__nvvm_f2ui_rz_ftz, "Uif", "nc")
|
||||
BUILTIN(__nvvm_f2ui_rz, "Uif", "nc")
|
||||
BUILTIN(__nvvm_f2ui_rm_ftz, "Uif", "nc")
|
||||
BUILTIN(__nvvm_f2ui_rm, "Uif", "nc")
|
||||
BUILTIN(__nvvm_f2ui_rp_ftz, "Uif", "nc")
|
||||
BUILTIN(__nvvm_f2ui_rp, "Uif", "nc")
|
||||
BUILTIN(__nvvm_i2f_rn, "fi", "nc")
|
||||
BUILTIN(__nvvm_i2f_rz, "fi", "nc")
|
||||
BUILTIN(__nvvm_i2f_rm, "fi", "nc")
|
||||
BUILTIN(__nvvm_i2f_rp, "fi", "nc")
|
||||
BUILTIN(__nvvm_ui2f_rn, "fUi", "nc")
|
||||
BUILTIN(__nvvm_ui2f_rz, "fUi", "nc")
|
||||
BUILTIN(__nvvm_ui2f_rm, "fUi", "nc")
|
||||
BUILTIN(__nvvm_ui2f_rp, "fUi", "nc")
|
||||
BUILTIN(__nvvm_lohi_i2d, "dii", "nc")
|
||||
BUILTIN(__nvvm_d2i_lo, "id", "nc")
|
||||
BUILTIN(__nvvm_d2i_hi, "id", "nc")
|
||||
BUILTIN(__nvvm_f2ll_rn_ftz, "LLif", "nc")
|
||||
BUILTIN(__nvvm_f2ll_rn, "LLif", "nc")
|
||||
BUILTIN(__nvvm_f2ll_rz_ftz, "LLif", "nc")
|
||||
BUILTIN(__nvvm_f2ll_rz, "LLif", "nc")
|
||||
BUILTIN(__nvvm_f2ll_rm_ftz, "LLif", "nc")
|
||||
BUILTIN(__nvvm_f2ll_rm, "LLif", "nc")
|
||||
BUILTIN(__nvvm_f2ll_rp_ftz, "LLif", "nc")
|
||||
BUILTIN(__nvvm_f2ll_rp, "LLif", "nc")
|
||||
BUILTIN(__nvvm_f2ull_rn_ftz, "ULLif", "nc")
|
||||
BUILTIN(__nvvm_f2ull_rn, "ULLif", "nc")
|
||||
BUILTIN(__nvvm_f2ull_rz_ftz, "ULLif", "nc")
|
||||
BUILTIN(__nvvm_f2ull_rz, "ULLif", "nc")
|
||||
BUILTIN(__nvvm_f2ull_rm_ftz, "ULLif", "nc")
|
||||
BUILTIN(__nvvm_f2ull_rm, "ULLif", "nc")
|
||||
BUILTIN(__nvvm_f2ull_rp_ftz, "ULLif", "nc")
|
||||
BUILTIN(__nvvm_f2ull_rp, "ULLif", "nc")
|
||||
BUILTIN(__nvvm_d2ll_rn, "LLid", "nc")
|
||||
BUILTIN(__nvvm_d2ll_rz, "LLid", "nc")
|
||||
BUILTIN(__nvvm_d2ll_rm, "LLid", "nc")
|
||||
BUILTIN(__nvvm_d2ll_rp, "LLid", "nc")
|
||||
BUILTIN(__nvvm_d2ull_rn, "ULLid", "nc")
|
||||
BUILTIN(__nvvm_d2ull_rz, "ULLid", "nc")
|
||||
BUILTIN(__nvvm_d2ull_rm, "ULLid", "nc")
|
||||
BUILTIN(__nvvm_d2ull_rp, "ULLid", "nc")
|
||||
BUILTIN(__nvvm_ll2f_rn, "fLLi", "nc")
|
||||
BUILTIN(__nvvm_ll2f_rz, "fLLi", "nc")
|
||||
BUILTIN(__nvvm_ll2f_rm, "fLLi", "nc")
|
||||
BUILTIN(__nvvm_ll2f_rp, "fLLi", "nc")
|
||||
BUILTIN(__nvvm_ull2f_rn, "fULLi", "nc")
|
||||
BUILTIN(__nvvm_ull2f_rz, "fULLi", "nc")
|
||||
BUILTIN(__nvvm_ull2f_rm, "fULLi", "nc")
|
||||
BUILTIN(__nvvm_ull2f_rp, "fULLi", "nc")
|
||||
BUILTIN(__nvvm_ll2d_rn, "dLLi", "nc")
|
||||
BUILTIN(__nvvm_ll2d_rz, "dLLi", "nc")
|
||||
BUILTIN(__nvvm_ll2d_rm, "dLLi", "nc")
|
||||
BUILTIN(__nvvm_ll2d_rp, "dLLi", "nc")
|
||||
BUILTIN(__nvvm_ull2d_rn, "dULLi", "nc")
|
||||
BUILTIN(__nvvm_ull2d_rz, "dULLi", "nc")
|
||||
BUILTIN(__nvvm_ull2d_rm, "dULLi", "nc")
|
||||
BUILTIN(__nvvm_ull2d_rp, "dULLi", "nc")
|
||||
BUILTIN(__nvvm_f2h_rn_ftz, "Usf", "nc")
|
||||
BUILTIN(__nvvm_f2h_rn, "Usf", "nc")
|
||||
BUILTIN(__nvvm_h2f, "fUs", "nc")
|
||||
BUILTIN(__nvvm_bitcast_i2f, "fi", "nc")
|
||||
BUILTIN(__nvvm_bitcast_f2i, "if", "nc")
|
||||
BUILTIN(__nvvm_bitcast_ll2d, "dLLi", "nc")
|
||||
BUILTIN(__nvvm_bitcast_d2ll, "LLid", "nc")
|
||||
|
||||
#undef BUILTIN
|
||||
|
@ -613,6 +613,12 @@ BUILTIN(__builtin_ia32_gatherd_d256, "V8iV8iV8iC*V8iV8iIc", "")
|
||||
BUILTIN(__builtin_ia32_gatherq_d, "V4iV4iV4iC*V2LLiV4iIc", "")
|
||||
BUILTIN(__builtin_ia32_gatherq_d256, "V4iV4iV4iC*V4LLiV4iIc", "")
|
||||
|
||||
// F16C
|
||||
BUILTIN(__builtin_ia32_vcvtps2ph, "V8sV4fIi", "")
|
||||
BUILTIN(__builtin_ia32_vcvtps2ph256, "V8sV8fIi", "")
|
||||
BUILTIN(__builtin_ia32_vcvtph2ps, "V4fV8s", "")
|
||||
BUILTIN(__builtin_ia32_vcvtph2ps256, "V8fV8s", "")
|
||||
|
||||
// RDRAND
|
||||
BUILTIN(__builtin_ia32_rdrand16_step, "UiUs*", "")
|
||||
BUILTIN(__builtin_ia32_rdrand32_step, "UiUi*", "")
|
||||
@ -730,5 +736,8 @@ BUILTIN(__builtin_ia32_vfrczps, "V4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_vfrczpd, "V2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_vfrczps256, "V8fV8f", "")
|
||||
BUILTIN(__builtin_ia32_vfrczpd256, "V4dV4d", "")
|
||||
BUILTIN(__builtin_ia32_xbegin, "i", "")
|
||||
BUILTIN(__builtin_ia32_xend, "v", "")
|
||||
BUILTIN(__builtin_ia32_xabort, "vIc", "")
|
||||
|
||||
#undef BUILTIN
|
||||
|
@ -147,7 +147,6 @@ ConversionResult ConvertUTF32toUTF8 (
|
||||
const UTF32** sourceStart, const UTF32* sourceEnd,
|
||||
UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags);
|
||||
|
||||
#ifdef CLANG_NEEDS_THESE_ONE_DAY
|
||||
ConversionResult ConvertUTF16toUTF32 (
|
||||
const UTF16** sourceStart, const UTF16* sourceEnd,
|
||||
UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags);
|
||||
@ -159,7 +158,9 @@ ConversionResult ConvertUTF32toUTF16 (
|
||||
|
||||
Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd);
|
||||
|
||||
Boolean isLegalUTF8String(const UTF8 *source, const UTF8 *sourceEnd);
|
||||
Boolean isLegalUTF8String(const UTF8 **source, const UTF8 *sourceEnd);
|
||||
|
||||
unsigned getNumBytesForUTF8(UTF8 firstByte);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
@ -175,11 +176,13 @@ namespace clang {
|
||||
* Convert an UTF8 StringRef to UTF8, UTF16, or UTF32 depending on
|
||||
* WideCharWidth. The converted data is written to ResultPtr, which needs to
|
||||
* point to at least WideCharWidth * (Source.Size() + 1) bytes. On success,
|
||||
* ResultPtr will point one after the end of the copied string.
|
||||
* ResultPtr will point one after the end of the copied string. On failure,
|
||||
* ResultPtr will not be changed, and ErrorPtr will be set to the location of
|
||||
* the first character which could not be converted.
|
||||
* \return true on success.
|
||||
*/
|
||||
bool ConvertUTF8toWide(unsigned WideCharWidth, llvm::StringRef Source,
|
||||
char *&ResultPtr);
|
||||
char *&ResultPtr, const UTF8 *&ErrorPtr);
|
||||
|
||||
/**
|
||||
* Convert an Unicode code point to UTF8 sequence.
|
||||
@ -194,7 +197,6 @@ bool ConvertUTF8toWide(unsigned WideCharWidth, llvm::StringRef Source,
|
||||
bool ConvertCodePointToUTF8(unsigned Source, char *&ResultPtr);
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -16,6 +16,7 @@
|
||||
#define LLVM_CLANG_DIAGNOSTIC_H
|
||||
|
||||
#include "clang/Basic/DiagnosticIDs.h"
|
||||
#include "clang/Basic/DiagnosticOptions.h"
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
@ -29,6 +30,7 @@
|
||||
namespace clang {
|
||||
class DiagnosticConsumer;
|
||||
class DiagnosticBuilder;
|
||||
class DiagnosticOptions;
|
||||
class IdentifierInfo;
|
||||
class DeclContext;
|
||||
class LangOptions;
|
||||
@ -160,13 +162,6 @@ class DiagnosticsEngine : public RefCountedBase<DiagnosticsEngine> {
|
||||
ak_qualtype_pair ///< pair<QualType, QualType>
|
||||
};
|
||||
|
||||
/// \brief Specifies which overload candidates to display when overload
|
||||
/// resolution fails.
|
||||
enum OverloadsShown {
|
||||
Ovl_All, ///< Show all overloads.
|
||||
Ovl_Best ///< Show just the "best" overload candidates.
|
||||
};
|
||||
|
||||
/// \brief Represents on argument value, which is a union discriminated
|
||||
/// by ArgumentKind, with a value.
|
||||
typedef std::pair<ArgumentKind, intptr_t> ArgumentValue;
|
||||
@ -190,6 +185,7 @@ class DiagnosticsEngine : public RefCountedBase<DiagnosticsEngine> {
|
||||
// backtrace stack, 0 -> no limit.
|
||||
ExtensionHandling ExtBehavior; // Map extensions onto warnings or errors?
|
||||
IntrusiveRefCntPtr<DiagnosticIDs> Diags;
|
||||
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
|
||||
DiagnosticConsumer *Client;
|
||||
bool OwnsDiagClient;
|
||||
SourceManager *SourceMgr;
|
||||
@ -341,6 +337,7 @@ class DiagnosticsEngine : public RefCountedBase<DiagnosticsEngine> {
|
||||
public:
|
||||
explicit DiagnosticsEngine(
|
||||
const IntrusiveRefCntPtr<DiagnosticIDs> &Diags,
|
||||
DiagnosticOptions *DiagOpts,
|
||||
DiagnosticConsumer *client = 0,
|
||||
bool ShouldOwnClient = true);
|
||||
~DiagnosticsEngine();
|
||||
@ -349,6 +346,9 @@ class DiagnosticsEngine : public RefCountedBase<DiagnosticsEngine> {
|
||||
return Diags;
|
||||
}
|
||||
|
||||
/// \brief Retrieve the diagnostic options.
|
||||
DiagnosticOptions &getDiagnosticOptions() const { return *DiagOpts; }
|
||||
|
||||
DiagnosticConsumer *getClient() { return Client; }
|
||||
const DiagnosticConsumer *getClient() const { return Client; }
|
||||
|
||||
@ -478,10 +478,13 @@ class DiagnosticsEngine : public RefCountedBase<DiagnosticsEngine> {
|
||||
}
|
||||
OverloadsShown getShowOverloads() const { return ShowOverloads; }
|
||||
|
||||
/// \brief Pretend that the last diagnostic issued was ignored.
|
||||
/// \brief Pretend that the last diagnostic issued was ignored, so any
|
||||
/// subsequent notes will be suppressed.
|
||||
///
|
||||
/// This can be used by clients who suppress diagnostics themselves.
|
||||
void setLastDiagnosticIgnored() {
|
||||
if (LastDiagLevel == DiagnosticIDs::Fatal)
|
||||
FatalErrorOccurred = true;
|
||||
LastDiagLevel = DiagnosticIDs::Ignored;
|
||||
}
|
||||
|
||||
@ -584,7 +587,7 @@ class DiagnosticsEngine : public RefCountedBase<DiagnosticsEngine> {
|
||||
const char *Argument, unsigned ArgLen,
|
||||
const ArgumentValue *PrevArgs, unsigned NumPrevArgs,
|
||||
SmallVectorImpl<char> &Output,
|
||||
SmallVectorImpl<intptr_t> &QualTypeVals) const {
|
||||
ArrayRef<intptr_t> QualTypeVals) const {
|
||||
ArgToStringFn(Kind, Val, Modifier, ModLen, Argument, ArgLen,
|
||||
PrevArgs, NumPrevArgs, Output, ArgToStringCookie,
|
||||
QualTypeVals);
|
||||
@ -837,7 +840,7 @@ class DiagnosticBuilder {
|
||||
/// call to ForceEmit.
|
||||
mutable bool IsForceEmit;
|
||||
|
||||
void operator=(const DiagnosticBuilder&); // DO NOT IMPLEMENT
|
||||
void operator=(const DiagnosticBuilder &) LLVM_DELETED_FUNCTION;
|
||||
friend class DiagnosticsEngine;
|
||||
|
||||
DiagnosticBuilder()
|
||||
@ -961,6 +964,10 @@ class DiagnosticBuilder {
|
||||
"Too many arguments to diagnostic!");
|
||||
DiagObj->DiagFixItHints[NumFixits++] = Hint;
|
||||
}
|
||||
|
||||
bool hasMaxRanges() const {
|
||||
return NumRanges == DiagnosticsEngine::MaxRanges;
|
||||
}
|
||||
};
|
||||
|
||||
inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
|
||||
|
@ -137,7 +137,7 @@ def err_odr_function_type_inconsistent : Error<
|
||||
def warn_odr_tag_type_inconsistent : Warning<
|
||||
"type %0 has incompatible definitions in different translation units">;
|
||||
def note_odr_tag_kind_here: Note<
|
||||
"%0 is a %select{struct|union|class|enum}1 here">;
|
||||
"%0 is a %select{struct|interface|union|class|enum}1 here">;
|
||||
def note_odr_field : Note<"field %0 has type %1 here">;
|
||||
def note_odr_missing_field : Note<"no corresponding field here">;
|
||||
def note_odr_bit_field : Note<"bit-field %0 with type %1 and length %2 here">;
|
||||
|
@ -121,5 +121,21 @@ def warn_doc_returns_attached_to_a_void_function : Warning<
|
||||
"method returning void}1">,
|
||||
InGroup<Documentation>, DefaultIgnore;
|
||||
|
||||
// \deprecated command
|
||||
|
||||
def warn_doc_deprecated_not_sync : Warning<
|
||||
"declaration is marked with '\\deprecated' command but does not have "
|
||||
"a deprecation attribute">,
|
||||
InGroup<DocumentationDeprecatedSync>, DefaultIgnore;
|
||||
|
||||
def note_add_deprecation_attr : Note<
|
||||
"add a deprecation attribute to the declaration to silence this warning">;
|
||||
|
||||
// verbatim block commands
|
||||
|
||||
def warn_verbatim_block_end_without_start : Warning<
|
||||
"'\\%0' command does not terminate a verbatim text block">,
|
||||
InGroup<Documentation>, DefaultIgnore;
|
||||
|
||||
} // end of documentation issue category
|
||||
} // end of AST component
|
||||
|
@ -78,9 +78,12 @@ def note_decl_hiding_tag_type : Note<
|
||||
"%1 %0 is hidden by a non-type declaration of %0 here">;
|
||||
|
||||
// Sema && Lex
|
||||
def ext_longlong : Extension<
|
||||
def ext_c99_longlong : Extension<
|
||||
"'long long' is an extension when C99 mode is not enabled">,
|
||||
InGroup<LongLong>;
|
||||
def ext_cxx11_longlong : Extension<
|
||||
"'long long' is a C++11 extension">,
|
||||
InGroup<CXX11LongLong>;
|
||||
def warn_cxx98_compat_longlong : Warning<
|
||||
"'long long' is incompatible with C++98">,
|
||||
InGroup<CXX98CompatPedantic>, DefaultIgnore;
|
||||
|
@ -11,6 +11,8 @@ let Component = "Driver" in {
|
||||
|
||||
def err_drv_no_such_file : Error<"no such file or directory: '%0'">;
|
||||
def err_drv_unsupported_opt : Error<"unsupported option '%0'">;
|
||||
def err_drv_unsupported_opt_for_target : Error<
|
||||
"unsupported option '%0' for target '%1'">;
|
||||
def err_drv_unsupported_option_argument : Error<
|
||||
"unsupported argument '%1' to option '%0'">;
|
||||
def err_drv_unknown_stdin_type : Error<
|
||||
@ -91,10 +93,10 @@ def err_drv_invalid_arch_for_deployment_target : Error<
|
||||
"invalid architecture '%0' for deployment target '%1'">;
|
||||
def err_drv_objc_gc_arr : Error<
|
||||
"cannot specify both '-fobjc-arc' and '%0'">;
|
||||
def err_arc_nonfragile_abi : Error<
|
||||
"-fobjc-arc is not supported with legacy abi">;
|
||||
def err_arc_unsupported : Error<
|
||||
"-fobjc-arc is not supported on current deployment target">;
|
||||
def err_arc_unsupported_on_runtime : Error<
|
||||
"-fobjc-arc is not supported on platforms using the legacy runtime">;
|
||||
def err_arc_unsupported_on_toolchain : Error< // feel free to generalize this
|
||||
"-fobjc-arc is not supported on versions of OS X prior to 10.6">;
|
||||
def err_drv_mg_requires_m_or_mm : Error<
|
||||
"option '-MG' requires '-M' or '-MM'">;
|
||||
def err_drv_asan_android_requires_pie : Error<
|
||||
@ -119,14 +121,10 @@ def warn_drv_unused_argument : Warning<
|
||||
def warn_drv_empty_joined_argument : Warning<
|
||||
"joined argument expects additional value: '%0'">,
|
||||
InGroup<DiagGroup<"unused-command-line-argument">>;
|
||||
def warn_drv_not_using_clang_cpp : Warning<
|
||||
"not using the clang preprocessor due to user override">;
|
||||
def warn_drv_not_using_clang_cxx : Warning<
|
||||
"not using the clang compiler for C++ inputs">;
|
||||
def warn_drv_not_using_clang_arch : Warning<
|
||||
"not using the clang compiler for the '%0' architecture">;
|
||||
def warn_drv_clang_unsupported : Warning<
|
||||
"the clang compiler does not support '%0'">;
|
||||
def warn_drv_deprecated_arg : Warning<
|
||||
"argument '%0' is deprecated, use '%1' instead">, InGroup<Deprecated>;
|
||||
def warn_drv_assuming_mfloat_abi_is : Warning<
|
||||
"unknown platform, assuming -mfloat-abi=%0">;
|
||||
def warn_ignoring_ftabstop_value : Warning<
|
||||
@ -141,5 +139,9 @@ def warn_drv_pch_not_first_include : Warning<
|
||||
|
||||
def note_drv_command_failed_diag_msg : Note<
|
||||
"diagnostic msg: %0">;
|
||||
|
||||
|
||||
def err_analyzer_config_no_value : Error<
|
||||
"analyzer-config option '%0' has a key but no value">;
|
||||
def err_analyzer_config_multiple_values : Error<
|
||||
"analyzer-config option '%0' should contain only one '='">;
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user