mirror of
https://github.com/opnsense/src.git
synced 2026-06-09 08:43:19 -04:00
Vendor import of clang trunk r161861:
http://llvm.org/svn/llvm-project/cfe/trunk@161861
This commit is contained in:
parent
41e20f564a
commit
56d91b49b1
1875 changed files with 112229 additions and 30719 deletions
6
.gitignore
vendored
6
.gitignore
vendored
|
|
@ -23,3 +23,9 @@
|
|||
#==============================================================================#
|
||||
cscope.files
|
||||
cscope.out
|
||||
|
||||
#==============================================================================#
|
||||
# Directories to ignore (do not add trailing '/'s, they skip symlinks).
|
||||
#==============================================================================#
|
||||
# Clang extra user tools, which is tracked independently (clang-tools-extra).
|
||||
tools/extra
|
||||
|
|
|
|||
|
|
@ -53,6 +53,14 @@ if( CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR )
|
|||
set(LLVM_TABLEGEN_EXE "${PATH_TO_LLVM_BUILD}/bin/Debug/llvm-tblgen${CMAKE_EXECUTABLE_SUFFIX}")
|
||||
endif()
|
||||
|
||||
# Define the default arguments to use with 'lit', and an option for the user
|
||||
# to override.
|
||||
set(LIT_ARGS_DEFAULT "-sv")
|
||||
if (MSVC OR XCODE)
|
||||
set(LIT_ARGS_DEFAULT "${LIT_ARGS_DEFAULT} --no-progress-bar")
|
||||
endif()
|
||||
set(LLVM_LIT_ARGS "${LIT_ARGS_DEFAULT}" CACHE STRING "Default options for lit")
|
||||
|
||||
set( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin )
|
||||
set( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib )
|
||||
set( CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib )
|
||||
|
|
@ -131,6 +139,10 @@ if (APPLE)
|
|||
set(CMAKE_MODULE_LINKER_FLAGS "-Wl,-flat_namespace -Wl,-undefined -Wl,suppress")
|
||||
endif ()
|
||||
|
||||
# libxml2 is an optional dependency, required only to run validation
|
||||
# tests on XML output.
|
||||
find_package(LibXml2)
|
||||
|
||||
configure_file(
|
||||
${CLANG_SOURCE_DIR}/include/clang/Config/config.h.cmake
|
||||
${CLANG_BINARY_DIR}/include/clang/Config/config.h)
|
||||
|
|
@ -192,20 +204,10 @@ macro(add_clang_library name)
|
|||
add_dependencies( ${name} ${LLVM_COMMON_DEPENDS} )
|
||||
endif( LLVM_COMMON_DEPENDS )
|
||||
|
||||
target_link_libraries( ${name} ${LLVM_USED_LIBS} )
|
||||
llvm_config( ${name} ${LLVM_LINK_COMPONENTS} )
|
||||
target_link_libraries( ${name} ${LLVM_COMMON_LIBS} )
|
||||
link_system_libs( ${name} )
|
||||
|
||||
add_dependencies(${name} ClangDiagnosticCommon)
|
||||
if(MSVC)
|
||||
get_target_property(cflag ${name} COMPILE_FLAGS)
|
||||
if(NOT cflag)
|
||||
set(cflag "")
|
||||
endif(NOT cflag)
|
||||
set(cflag "${cflag} /Za")
|
||||
set_target_properties(${name} PROPERTIES COMPILE_FLAGS ${cflag})
|
||||
endif(MSVC)
|
||||
install(TARGETS ${name}
|
||||
LIBRARY DESTINATION lib${LLVM_LIBDIR_SUFFIX}
|
||||
ARCHIVE DESTINATION lib${LLVM_LIBDIR_SUFFIX}
|
||||
|
|
@ -252,14 +254,14 @@ mark_as_advanced(CLANG_EXECUTABLE_VERSION LIBCLANG_LIBRARY_VERSION)
|
|||
|
||||
add_subdirectory(utils/TableGen)
|
||||
|
||||
option(CLANG_BUILD_EXAMPLES "Build CLANG example programs by default." OFF)
|
||||
add_subdirectory(examples)
|
||||
|
||||
add_subdirectory(include)
|
||||
add_subdirectory(lib)
|
||||
add_subdirectory(tools)
|
||||
add_subdirectory(runtime)
|
||||
|
||||
option(CLANG_BUILD_EXAMPLES "Build CLANG example programs by default." OFF)
|
||||
add_subdirectory(examples)
|
||||
|
||||
# TODO: docs.
|
||||
add_subdirectory(test)
|
||||
|
||||
|
|
@ -280,3 +282,4 @@ endif()
|
|||
|
||||
set(BUG_REPORT_URL "http://llvm.org/bugs/" CACHE STRING
|
||||
"Default URL where bug reports are to be submitted.")
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
34
bindings/python/clang/enumerations.py
Normal file
34
bindings/python/clang/enumerations.py
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
#===- enumerations.py - Python Enumerations ------------------*- python -*--===#
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
#===------------------------------------------------------------------------===#
|
||||
|
||||
"""
|
||||
Clang Enumerations
|
||||
==================
|
||||
|
||||
This module provides static definitions of enumerations that exist in libclang.
|
||||
|
||||
Enumerations are typically defined as a list of tuples. The exported values are
|
||||
typically munged into other types or classes at module load time.
|
||||
|
||||
All enumerations are centrally defined in this file so they are all grouped
|
||||
together and easier to audit. And, maybe even one day this file will be
|
||||
automatically generated by scanning the libclang headers!
|
||||
"""
|
||||
|
||||
# Maps to CXTokenKind. Note that libclang maintains a separate set of token
|
||||
# enumerations from the C++ API.
|
||||
TokenKinds = [
|
||||
('PUNCTUATION', 0),
|
||||
('KEYWORD', 1),
|
||||
('IDENTIFIER', 2),
|
||||
('LITERAL', 3),
|
||||
('COMMENT', 4),
|
||||
]
|
||||
|
||||
__all__ = ['TokenKinds']
|
||||
17
bindings/python/tests/cindex/INPUTS/compile_commands.json
Normal file
17
bindings/python/tests/cindex/INPUTS/compile_commands.json
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
[
|
||||
{
|
||||
"directory": "/home/john.doe/MyProject",
|
||||
"command": "clang++ -o project.o -c /home/john.doe/MyProject/project.cpp",
|
||||
"file": "/home/john.doe/MyProject/project.cpp"
|
||||
},
|
||||
{
|
||||
"directory": "/home/john.doe/MyProjectA",
|
||||
"command": "clang++ -o project2.o -c /home/john.doe/MyProject/project2.cpp",
|
||||
"file": "/home/john.doe/MyProject/project2.cpp"
|
||||
},
|
||||
{
|
||||
"directory": "/home/john.doe/MyProjectB",
|
||||
"command": "clang++ -DFEATURE=1 -o project2-feature.o -c /home/john.doe/MyProject/project2.cpp",
|
||||
"file": "/home/john.doe/MyProject/project2.cpp"
|
||||
}
|
||||
]
|
||||
89
bindings/python/tests/cindex/test_cdb.py
Normal file
89
bindings/python/tests/cindex/test_cdb.py
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
from clang.cindex import CompilationDatabase
|
||||
from clang.cindex import CompilationDatabaseError
|
||||
from clang.cindex import CompileCommands
|
||||
from clang.cindex import CompileCommand
|
||||
import os
|
||||
import gc
|
||||
|
||||
kInputsDir = os.path.join(os.path.dirname(__file__), 'INPUTS')
|
||||
|
||||
def test_create_fail():
|
||||
"""Check we fail loading a database with an assertion"""
|
||||
path = os.path.dirname(__file__)
|
||||
try:
|
||||
cdb = CompilationDatabase.fromDirectory(path)
|
||||
except CompilationDatabaseError as e:
|
||||
assert e.cdb_error == CompilationDatabaseError.ERROR_CANNOTLOADDATABASE
|
||||
else:
|
||||
assert False
|
||||
|
||||
def test_create():
|
||||
"""Check we can load a compilation database"""
|
||||
cdb = CompilationDatabase.fromDirectory(kInputsDir)
|
||||
|
||||
def test_lookup_fail():
|
||||
"""Check file lookup failure"""
|
||||
cdb = CompilationDatabase.fromDirectory(kInputsDir)
|
||||
assert cdb.getCompileCommands('file_do_not_exist.cpp') == None
|
||||
|
||||
def test_lookup_succeed():
|
||||
"""Check we get some results if the file exists in the db"""
|
||||
cdb = CompilationDatabase.fromDirectory(kInputsDir)
|
||||
cmds = cdb.getCompileCommands('/home/john.doe/MyProject/project.cpp')
|
||||
assert len(cmds) != 0
|
||||
|
||||
def test_1_compilecommand():
|
||||
"""Check file with single compile command"""
|
||||
cdb = CompilationDatabase.fromDirectory(kInputsDir)
|
||||
cmds = cdb.getCompileCommands('/home/john.doe/MyProject/project.cpp')
|
||||
assert len(cmds) == 1
|
||||
assert cmds[0].directory == '/home/john.doe/MyProject'
|
||||
expected = [ 'clang++', '-o', 'project.o', '-c',
|
||||
'/home/john.doe/MyProject/project.cpp']
|
||||
for arg, exp in zip(cmds[0].arguments, expected):
|
||||
assert arg == exp
|
||||
|
||||
def test_2_compilecommand():
|
||||
"""Check file with 2 compile commands"""
|
||||
cdb = CompilationDatabase.fromDirectory(kInputsDir)
|
||||
cmds = cdb.getCompileCommands('/home/john.doe/MyProject/project2.cpp')
|
||||
assert len(cmds) == 2
|
||||
expected = [
|
||||
{ 'wd': '/home/john.doe/MyProjectA',
|
||||
'line': ['clang++', '-o', 'project2.o', '-c',
|
||||
'/home/john.doe/MyProject/project2.cpp']},
|
||||
{ 'wd': '/home/john.doe/MyProjectB',
|
||||
'line': ['clang++', '-DFEATURE=1', '-o', 'project2-feature.o', '-c',
|
||||
'/home/john.doe/MyProject/project2.cpp']}
|
||||
]
|
||||
for i in range(len(cmds)):
|
||||
assert cmds[i].directory == expected[i]['wd']
|
||||
for arg, exp in zip(cmds[i].arguments, expected[i]['line']):
|
||||
assert arg == exp
|
||||
|
||||
def test_compilecommand_iterator_stops():
|
||||
"""Check that iterator stops after the correct number of elements"""
|
||||
cdb = CompilationDatabase.fromDirectory(kInputsDir)
|
||||
count = 0
|
||||
for cmd in cdb.getCompileCommands('/home/john.doe/MyProject/project2.cpp'):
|
||||
count += 1
|
||||
assert count <= 2
|
||||
|
||||
def test_compilationDB_references():
|
||||
"""Ensure CompilationsCommands are independent of the database"""
|
||||
cdb = CompilationDatabase.fromDirectory(kInputsDir)
|
||||
cmds = cdb.getCompileCommands('/home/john.doe/MyProject/project.cpp')
|
||||
del cdb
|
||||
gc.collect()
|
||||
workingdir = cmds[0].directory
|
||||
|
||||
def test_compilationCommands_references():
|
||||
"""Ensure CompilationsCommand keeps a reference to CompilationCommands"""
|
||||
cdb = CompilationDatabase.fromDirectory(kInputsDir)
|
||||
cmds = cdb.getCompileCommands('/home/john.doe/MyProject/project.cpp')
|
||||
del cdb
|
||||
cmd0 = cmds[0]
|
||||
del cmds
|
||||
gc.collect()
|
||||
workingdir = cmd0.directory
|
||||
|
||||
|
|
@ -1,6 +1,10 @@
|
|||
import gc
|
||||
|
||||
from clang.cindex import CursorKind
|
||||
from clang.cindex import TranslationUnit
|
||||
from clang.cindex import TypeKind
|
||||
from .util import get_cursor
|
||||
from .util import get_cursors
|
||||
from .util import get_tu
|
||||
|
||||
kInput = """\
|
||||
|
|
@ -37,6 +41,8 @@ def test_get_children():
|
|||
tu_nodes = list(it)
|
||||
|
||||
assert len(tu_nodes) == 3
|
||||
for cursor in tu_nodes:
|
||||
assert cursor.translation_unit is not None
|
||||
|
||||
assert tu_nodes[0] != tu_nodes[1]
|
||||
assert tu_nodes[0].kind == CursorKind.STRUCT_DECL
|
||||
|
|
@ -46,6 +52,7 @@ def test_get_children():
|
|||
assert tu_nodes[0].location.line == 4
|
||||
assert tu_nodes[0].location.column == 8
|
||||
assert tu_nodes[0].hash > 0
|
||||
assert tu_nodes[0].translation_unit is not None
|
||||
|
||||
s0_nodes = list(tu_nodes[0].get_children())
|
||||
assert len(s0_nodes) == 2
|
||||
|
|
@ -66,6 +73,51 @@ def test_get_children():
|
|||
assert tu_nodes[2].displayname == 'f0(int, int)'
|
||||
assert tu_nodes[2].is_definition() == True
|
||||
|
||||
def test_references():
|
||||
"""Ensure that references to TranslationUnit are kept."""
|
||||
tu = get_tu('int x;')
|
||||
cursors = list(tu.cursor.get_children())
|
||||
assert len(cursors) > 0
|
||||
|
||||
cursor = cursors[0]
|
||||
assert isinstance(cursor.translation_unit, TranslationUnit)
|
||||
|
||||
# Delete reference to TU and perform a full GC.
|
||||
del tu
|
||||
gc.collect()
|
||||
assert isinstance(cursor.translation_unit, TranslationUnit)
|
||||
|
||||
# If the TU was destroyed, this should cause a segfault.
|
||||
parent = cursor.semantic_parent
|
||||
|
||||
def test_canonical():
|
||||
source = 'struct X; struct X; struct X { int member; };'
|
||||
tu = get_tu(source)
|
||||
|
||||
cursors = []
|
||||
for cursor in tu.cursor.get_children():
|
||||
if cursor.spelling == 'X':
|
||||
cursors.append(cursor)
|
||||
|
||||
assert len(cursors) == 3
|
||||
assert cursors[1].canonical == cursors[2].canonical
|
||||
|
||||
def test_is_static_method():
|
||||
"""Ensure Cursor.is_static_method works."""
|
||||
|
||||
source = 'class X { static void foo(); void bar(); };'
|
||||
tu = get_tu(source, lang='cpp')
|
||||
|
||||
cls = get_cursor(tu, 'X')
|
||||
foo = get_cursor(tu, 'foo')
|
||||
bar = get_cursor(tu, 'bar')
|
||||
assert cls is not None
|
||||
assert foo is not None
|
||||
assert bar is not None
|
||||
|
||||
assert foo.is_static_method()
|
||||
assert not bar.is_static_method()
|
||||
|
||||
def test_underlying_type():
|
||||
tu = get_tu('typedef int foo;')
|
||||
typedef = get_cursor(tu, 'foo')
|
||||
|
|
@ -75,6 +127,30 @@ def test_underlying_type():
|
|||
underlying = typedef.underlying_typedef_type
|
||||
assert underlying.kind == TypeKind.INT
|
||||
|
||||
kParentTest = """\
|
||||
class C {
|
||||
void f();
|
||||
}
|
||||
|
||||
void C::f() { }
|
||||
"""
|
||||
def test_semantic_parent():
|
||||
tu = get_tu(kParentTest, 'cpp')
|
||||
curs = get_cursors(tu, 'f')
|
||||
decl = get_cursor(tu, 'C')
|
||||
assert(len(curs) == 2)
|
||||
assert(curs[0].semantic_parent == curs[1].semantic_parent)
|
||||
assert(curs[0].semantic_parent == decl)
|
||||
|
||||
def test_lexical_parent():
|
||||
tu = get_tu(kParentTest, 'cpp')
|
||||
curs = get_cursors(tu, 'f')
|
||||
decl = get_cursor(tu, 'C')
|
||||
assert(len(curs) == 2)
|
||||
assert(curs[0].lexical_parent != curs[1].lexical_parent)
|
||||
assert(curs[0].lexical_parent == decl)
|
||||
assert(curs[1].lexical_parent == tu.cursor)
|
||||
|
||||
def test_enum_type():
|
||||
tu = get_tu('enum TEST { FOO=1, BAR=2 };')
|
||||
enum = get_cursor(tu, 'TEST')
|
||||
|
|
@ -84,9 +160,84 @@ def test_enum_type():
|
|||
enum_type = enum.enum_type
|
||||
assert enum_type.kind == TypeKind.UINT
|
||||
|
||||
def test_enum_type_cpp():
|
||||
tu = get_tu('enum TEST : long long { FOO=1, BAR=2 };', lang="cpp")
|
||||
enum = get_cursor(tu, 'TEST')
|
||||
assert enum is not None
|
||||
|
||||
assert enum.kind == CursorKind.ENUM_DECL
|
||||
assert enum.enum_type.kind == TypeKind.LONGLONG
|
||||
|
||||
def test_objc_type_encoding():
|
||||
tu = get_tu('int i;', lang='objc')
|
||||
i = get_cursor(tu, 'i')
|
||||
|
||||
assert i is not None
|
||||
assert i.objc_type_encoding == 'i'
|
||||
|
||||
def test_enum_values():
|
||||
tu = get_tu('enum TEST { SPAM=1, EGG, HAM = EGG * 20};')
|
||||
enum = get_cursor(tu, 'TEST')
|
||||
assert enum is not None
|
||||
|
||||
assert enum.kind == CursorKind.ENUM_DECL
|
||||
|
||||
enum_constants = list(enum.get_children())
|
||||
assert len(enum_constants) == 3
|
||||
|
||||
spam, egg, ham = enum_constants
|
||||
|
||||
assert spam.kind == CursorKind.ENUM_CONSTANT_DECL
|
||||
assert spam.enum_value == 1
|
||||
assert egg.kind == CursorKind.ENUM_CONSTANT_DECL
|
||||
assert egg.enum_value == 2
|
||||
assert ham.kind == CursorKind.ENUM_CONSTANT_DECL
|
||||
assert ham.enum_value == 40
|
||||
|
||||
def test_enum_values_cpp():
|
||||
tu = get_tu('enum TEST : long long { SPAM = -1, HAM = 0x10000000000};', lang="cpp")
|
||||
enum = get_cursor(tu, 'TEST')
|
||||
assert enum is not None
|
||||
|
||||
assert enum.kind == CursorKind.ENUM_DECL
|
||||
|
||||
enum_constants = list(enum.get_children())
|
||||
assert len(enum_constants) == 2
|
||||
|
||||
spam, ham = enum_constants
|
||||
|
||||
assert spam.kind == CursorKind.ENUM_CONSTANT_DECL
|
||||
assert spam.enum_value == -1
|
||||
assert ham.kind == CursorKind.ENUM_CONSTANT_DECL
|
||||
assert ham.enum_value == 0x10000000000
|
||||
|
||||
def test_annotation_attribute():
|
||||
tu = get_tu('int foo (void) __attribute__ ((annotate("here be annotation attribute")));')
|
||||
|
||||
foo = get_cursor(tu, 'foo')
|
||||
assert foo is not None
|
||||
|
||||
for c in foo.get_children():
|
||||
if c.kind == CursorKind.ANNOTATE_ATTR:
|
||||
assert c.displayname == "here be annotation attribute"
|
||||
break
|
||||
else:
|
||||
assert False, "Couldn't find annotation"
|
||||
|
||||
def test_result_type():
|
||||
tu = get_tu('int foo();')
|
||||
foo = get_cursor(tu, 'foo')
|
||||
|
||||
assert foo is not None
|
||||
t = foo.result_type
|
||||
assert t.kind == TypeKind.INT
|
||||
|
||||
def test_get_tokens():
|
||||
"""Ensure we can map cursors back to tokens."""
|
||||
tu = get_tu('int foo(int i);')
|
||||
foo = get_cursor(tu, 'foo')
|
||||
|
||||
tokens = list(foo.get_tokens())
|
||||
assert len(tokens) == 7
|
||||
assert tokens[0].spelling == 'int'
|
||||
assert tokens[1].spelling == 'foo'
|
||||
|
|
|
|||
|
|
@ -60,6 +60,15 @@ def test_location():
|
|||
location3 = SourceLocation.from_position(tu, file, 1, 4)
|
||||
assert location2 != location3
|
||||
|
||||
offset_location = SourceLocation.from_offset(tu, file, 5)
|
||||
cursor = Cursor.from_location(tu, offset_location)
|
||||
verified = False
|
||||
for n in [n for n in tu.cursor.get_children() if n.spelling == 'one']:
|
||||
assert n == cursor
|
||||
verified = True
|
||||
|
||||
assert verified
|
||||
|
||||
def test_extent():
|
||||
tu = get_tu(baseInput)
|
||||
one = get_cursor(tu, 'one')
|
||||
|
|
|
|||
43
bindings/python/tests/cindex/test_token_kind.py
Normal file
43
bindings/python/tests/cindex/test_token_kind.py
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
from clang.cindex import TokenKind
|
||||
from nose.tools import eq_
|
||||
from nose.tools import ok_
|
||||
from nose.tools import raises
|
||||
|
||||
def test_constructor():
|
||||
"""Ensure TokenKind constructor works as expected."""
|
||||
|
||||
t = TokenKind(5, 'foo')
|
||||
|
||||
eq_(t.value, 5)
|
||||
eq_(t.name, 'foo')
|
||||
|
||||
@raises(ValueError)
|
||||
def test_bad_register():
|
||||
"""Ensure a duplicate value is rejected for registration."""
|
||||
|
||||
TokenKind.register(2, 'foo')
|
||||
|
||||
@raises(ValueError)
|
||||
def test_unknown_value():
|
||||
"""Ensure trying to fetch an unknown value raises."""
|
||||
|
||||
TokenKind.from_value(-1)
|
||||
|
||||
def test_registration():
|
||||
"""Ensure that items registered appear as class attributes."""
|
||||
ok_(hasattr(TokenKind, 'LITERAL'))
|
||||
literal = TokenKind.LITERAL
|
||||
|
||||
ok_(isinstance(literal, TokenKind))
|
||||
|
||||
def test_from_value():
|
||||
"""Ensure registered values can be obtained from from_value()."""
|
||||
t = TokenKind.from_value(3)
|
||||
ok_(isinstance(t, TokenKind))
|
||||
eq_(t, TokenKind.LITERAL)
|
||||
|
||||
def test_repr():
|
||||
"""Ensure repr() works."""
|
||||
|
||||
r = repr(TokenKind.LITERAL)
|
||||
eq_(r, 'TokenKind.LITERAL')
|
||||
52
bindings/python/tests/cindex/test_tokens.py
Normal file
52
bindings/python/tests/cindex/test_tokens.py
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
from clang.cindex import CursorKind
|
||||
from clang.cindex import Index
|
||||
from clang.cindex import SourceLocation
|
||||
from clang.cindex import SourceRange
|
||||
from clang.cindex import TokenKind
|
||||
from nose.tools import eq_
|
||||
from nose.tools import ok_
|
||||
|
||||
from .util import get_tu
|
||||
|
||||
def test_token_to_cursor():
|
||||
"""Ensure we can obtain a Cursor from a Token instance."""
|
||||
tu = get_tu('int i = 5;')
|
||||
r = tu.get_extent('t.c', (0, 9))
|
||||
tokens = list(tu.get_tokens(extent=r))
|
||||
|
||||
assert len(tokens) == 5
|
||||
assert tokens[1].spelling == 'i'
|
||||
assert tokens[1].kind == TokenKind.IDENTIFIER
|
||||
|
||||
cursor = tokens[1].cursor
|
||||
assert cursor.kind == CursorKind.VAR_DECL
|
||||
assert tokens[1].cursor == tokens[2].cursor
|
||||
|
||||
def test_token_location():
|
||||
"""Ensure Token.location works."""
|
||||
|
||||
tu = get_tu('int foo = 10;')
|
||||
r = tu.get_extent('t.c', (0, 11))
|
||||
|
||||
tokens = list(tu.get_tokens(extent=r))
|
||||
eq_(len(tokens), 4)
|
||||
|
||||
loc = tokens[1].location
|
||||
ok_(isinstance(loc, SourceLocation))
|
||||
eq_(loc.line, 1)
|
||||
eq_(loc.column, 5)
|
||||
eq_(loc.offset, 4)
|
||||
|
||||
def test_token_extent():
|
||||
"""Ensure Token.extent works."""
|
||||
tu = get_tu('int foo = 10;')
|
||||
r = tu.get_extent('t.c', (0, 11))
|
||||
|
||||
tokens = list(tu.get_tokens(extent=r))
|
||||
eq_(len(tokens), 4)
|
||||
|
||||
extent = tokens[1].extent
|
||||
ok_(isinstance(extent, SourceRange))
|
||||
|
||||
eq_(extent.start.offset, 4)
|
||||
eq_(extent.end.offset, 7)
|
||||
|
|
@ -1,42 +1,48 @@
|
|||
from clang.cindex import *
|
||||
import gc
|
||||
import os
|
||||
|
||||
from clang.cindex import CursorKind
|
||||
from clang.cindex import Cursor
|
||||
from clang.cindex import File
|
||||
from clang.cindex import Index
|
||||
from clang.cindex import SourceLocation
|
||||
from clang.cindex import SourceRange
|
||||
from clang.cindex import TranslationUnitSaveError
|
||||
from clang.cindex import TranslationUnit
|
||||
from .util import get_cursor
|
||||
from .util import get_tu
|
||||
|
||||
kInputsDir = os.path.join(os.path.dirname(__file__), 'INPUTS')
|
||||
|
||||
def test_spelling():
|
||||
path = os.path.join(kInputsDir, 'hello.cpp')
|
||||
index = Index.create()
|
||||
tu = index.parse(path)
|
||||
tu = TranslationUnit.from_source(path)
|
||||
assert tu.spelling == path
|
||||
|
||||
def test_cursor():
|
||||
path = os.path.join(kInputsDir, 'hello.cpp')
|
||||
index = Index.create()
|
||||
tu = index.parse(path)
|
||||
tu = get_tu(path)
|
||||
c = tu.cursor
|
||||
assert isinstance(c, Cursor)
|
||||
assert c.kind is CursorKind.TRANSLATION_UNIT
|
||||
|
||||
def test_parse_arguments():
|
||||
path = os.path.join(kInputsDir, 'parse_arguments.c')
|
||||
index = Index.create()
|
||||
tu = index.parse(path, ['-DDECL_ONE=hello', '-DDECL_TWO=hi'])
|
||||
tu = TranslationUnit.from_source(path, ['-DDECL_ONE=hello', '-DDECL_TWO=hi'])
|
||||
spellings = [c.spelling for c in tu.cursor.get_children()]
|
||||
assert spellings[-2] == 'hello'
|
||||
assert spellings[-1] == 'hi'
|
||||
|
||||
def test_reparse_arguments():
|
||||
path = os.path.join(kInputsDir, 'parse_arguments.c')
|
||||
index = Index.create()
|
||||
tu = index.parse(path, ['-DDECL_ONE=hello', '-DDECL_TWO=hi'])
|
||||
tu = TranslationUnit.from_source(path, ['-DDECL_ONE=hello', '-DDECL_TWO=hi'])
|
||||
tu.reparse()
|
||||
spellings = [c.spelling for c in tu.cursor.get_children()]
|
||||
assert spellings[-2] == 'hello'
|
||||
assert spellings[-1] == 'hi'
|
||||
|
||||
def test_unsaved_files():
|
||||
index = Index.create()
|
||||
tu = index.parse('fake.c', ['-I./'], unsaved_files = [
|
||||
tu = TranslationUnit.from_source('fake.c', ['-I./'], unsaved_files = [
|
||||
('fake.c', """
|
||||
#include "fake.h"
|
||||
int x;
|
||||
|
|
@ -52,8 +58,7 @@ int SOME_DEFINE;
|
|||
|
||||
def test_unsaved_files_2():
|
||||
import StringIO
|
||||
index = Index.create()
|
||||
tu = index.parse('fake.c', unsaved_files = [
|
||||
tu = TranslationUnit.from_source('fake.c', unsaved_files = [
|
||||
('fake.c', StringIO.StringIO('int x;'))])
|
||||
spellings = [c.spelling for c in tu.cursor.get_children()]
|
||||
assert spellings[-1] == 'x'
|
||||
|
|
@ -78,7 +83,159 @@ def test_includes():
|
|||
h3 = os.path.join(kInputsDir, "header3.h")
|
||||
inc = [(src, h1), (h1, h3), (src, h2), (h2, h3)]
|
||||
|
||||
index = Index.create()
|
||||
tu = index.parse(src)
|
||||
tu = TranslationUnit.from_source(src)
|
||||
for i in zip(inc, tu.get_includes()):
|
||||
assert eq(i[0], i[1])
|
||||
|
||||
def save_tu(tu):
|
||||
"""Convenience API to save a TranslationUnit to a file.
|
||||
|
||||
Returns the filename it was saved to.
|
||||
"""
|
||||
|
||||
# FIXME Generate a temp file path using system APIs.
|
||||
base = 'TEMP_FOR_TRANSLATIONUNIT_SAVE.c'
|
||||
path = os.path.join(kInputsDir, base)
|
||||
|
||||
# Just in case.
|
||||
if os.path.exists(path):
|
||||
os.unlink(path)
|
||||
|
||||
tu.save(path)
|
||||
|
||||
return path
|
||||
|
||||
def test_save():
|
||||
"""Ensure TranslationUnit.save() works."""
|
||||
|
||||
tu = get_tu('int foo();')
|
||||
|
||||
path = save_tu(tu)
|
||||
assert os.path.exists(path)
|
||||
assert os.path.getsize(path) > 0
|
||||
os.unlink(path)
|
||||
|
||||
def test_save_translation_errors():
|
||||
"""Ensure that saving to an invalid directory raises."""
|
||||
|
||||
tu = get_tu('int foo();')
|
||||
|
||||
path = '/does/not/exist/llvm-test.ast'
|
||||
assert not os.path.exists(os.path.dirname(path))
|
||||
|
||||
try:
|
||||
tu.save(path)
|
||||
assert False
|
||||
except TranslationUnitSaveError as ex:
|
||||
expected = TranslationUnitSaveError.ERROR_UNKNOWN
|
||||
assert ex.save_error == expected
|
||||
|
||||
def test_load():
|
||||
"""Ensure TranslationUnits can be constructed from saved files."""
|
||||
|
||||
tu = get_tu('int foo();')
|
||||
assert len(tu.diagnostics) == 0
|
||||
path = save_tu(tu)
|
||||
|
||||
assert os.path.exists(path)
|
||||
assert os.path.getsize(path) > 0
|
||||
|
||||
tu2 = TranslationUnit.from_ast_file(filename=path)
|
||||
assert len(tu2.diagnostics) == 0
|
||||
|
||||
foo = get_cursor(tu2, 'foo')
|
||||
assert foo is not None
|
||||
|
||||
# Just in case there is an open file descriptor somewhere.
|
||||
del tu2
|
||||
|
||||
os.unlink(path)
|
||||
|
||||
def test_index_parse():
|
||||
path = os.path.join(kInputsDir, 'hello.cpp')
|
||||
index = Index.create()
|
||||
tu = index.parse(path)
|
||||
assert isinstance(tu, TranslationUnit)
|
||||
|
||||
def test_get_file():
|
||||
"""Ensure tu.get_file() works appropriately."""
|
||||
|
||||
tu = get_tu('int foo();')
|
||||
|
||||
f = tu.get_file('t.c')
|
||||
assert isinstance(f, File)
|
||||
assert f.name == 't.c'
|
||||
|
||||
try:
|
||||
f = tu.get_file('foobar.cpp')
|
||||
except:
|
||||
pass
|
||||
else:
|
||||
assert False
|
||||
|
||||
def test_get_source_location():
|
||||
"""Ensure tu.get_source_location() works."""
|
||||
|
||||
tu = get_tu('int foo();')
|
||||
|
||||
location = tu.get_location('t.c', 2)
|
||||
assert isinstance(location, SourceLocation)
|
||||
assert location.offset == 2
|
||||
assert location.file.name == 't.c'
|
||||
|
||||
location = tu.get_location('t.c', (1, 3))
|
||||
assert isinstance(location, SourceLocation)
|
||||
assert location.line == 1
|
||||
assert location.column == 3
|
||||
assert location.file.name == 't.c'
|
||||
|
||||
def test_get_source_range():
|
||||
"""Ensure tu.get_source_range() works."""
|
||||
|
||||
tu = get_tu('int foo();')
|
||||
|
||||
r = tu.get_extent('t.c', (1,4))
|
||||
assert isinstance(r, SourceRange)
|
||||
assert r.start.offset == 1
|
||||
assert r.end.offset == 4
|
||||
assert r.start.file.name == 't.c'
|
||||
assert r.end.file.name == 't.c'
|
||||
|
||||
r = tu.get_extent('t.c', ((1,2), (1,3)))
|
||||
assert isinstance(r, SourceRange)
|
||||
assert r.start.line == 1
|
||||
assert r.start.column == 2
|
||||
assert r.end.line == 1
|
||||
assert r.end.column == 3
|
||||
assert r.start.file.name == 't.c'
|
||||
assert r.end.file.name == 't.c'
|
||||
|
||||
start = tu.get_location('t.c', 0)
|
||||
end = tu.get_location('t.c', 5)
|
||||
|
||||
r = tu.get_extent('t.c', (start, end))
|
||||
assert isinstance(r, SourceRange)
|
||||
assert r.start.offset == 0
|
||||
assert r.end.offset == 5
|
||||
assert r.start.file.name == 't.c'
|
||||
assert r.end.file.name == 't.c'
|
||||
|
||||
def test_get_tokens_gc():
|
||||
"""Ensures get_tokens() works properly with garbage collection."""
|
||||
|
||||
tu = get_tu('int foo();')
|
||||
r = tu.get_extent('t.c', (0, 10))
|
||||
tokens = list(tu.get_tokens(extent=r))
|
||||
|
||||
assert tokens[0].spelling == 'int'
|
||||
gc.collect()
|
||||
assert tokens[0].spelling == 'int'
|
||||
|
||||
del tokens[1]
|
||||
gc.collect()
|
||||
assert tokens[0].spelling == 'int'
|
||||
|
||||
# May trigger segfault if we don't do our job properly.
|
||||
del tokens
|
||||
gc.collect()
|
||||
gc.collect() # Just in case.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
import gc
|
||||
|
||||
from clang.cindex import CursorKind
|
||||
from clang.cindex import TranslationUnit
|
||||
from clang.cindex import TypeKind
|
||||
from nose.tools import raises
|
||||
from .util import get_cursor
|
||||
|
|
@ -28,6 +31,7 @@ def test_a_struct():
|
|||
assert teststruct is not None, "Could not find teststruct."
|
||||
fields = list(teststruct.get_children())
|
||||
assert all(x.kind == CursorKind.FIELD_DECL for x in fields)
|
||||
assert all(x.translation_unit is not None for x in fields)
|
||||
|
||||
assert fields[0].spelling == 'a'
|
||||
assert not fields[0].type.is_const_qualified()
|
||||
|
|
@ -72,6 +76,26 @@ def test_a_struct():
|
|||
assert fields[7].type.get_pointee().get_pointee().kind == TypeKind.POINTER
|
||||
assert fields[7].type.get_pointee().get_pointee().get_pointee().kind == TypeKind.INT
|
||||
|
||||
def test_references():
|
||||
"""Ensure that a Type maintains a reference to a TranslationUnit."""
|
||||
|
||||
tu = get_tu('int x;')
|
||||
children = list(tu.cursor.get_children())
|
||||
assert len(children) > 0
|
||||
|
||||
cursor = children[0]
|
||||
t = cursor.type
|
||||
|
||||
assert isinstance(t.translation_unit, TranslationUnit)
|
||||
|
||||
# Delete main TranslationUnit reference and force a GC.
|
||||
del tu
|
||||
gc.collect()
|
||||
assert isinstance(t.translation_unit, TranslationUnit)
|
||||
|
||||
# If the TU was destroyed, this should cause a segfault.
|
||||
decl = t.get_declaration()
|
||||
|
||||
constarrayInput="""
|
||||
struct teststruct {
|
||||
void *A[2];
|
||||
|
|
@ -263,7 +287,7 @@ def test_is_volatile_qualified():
|
|||
def test_is_restrict_qualified():
|
||||
"""Ensure Type.is_restrict_qualified works."""
|
||||
|
||||
tu = get_tu('struct s { void * restrict i; void * j };')
|
||||
tu = get_tu('struct s { void * restrict i; void * j; };')
|
||||
|
||||
i = get_cursor(tu, 'i')
|
||||
j = get_cursor(tu, 'j')
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# This file provides common utility functions for the test suite.
|
||||
|
||||
from clang.cindex import Cursor
|
||||
from clang.cindex import Index
|
||||
from clang.cindex import TranslationUnit
|
||||
|
||||
def get_tu(source, lang='c', all_warnings=False):
|
||||
"""Obtain a translation unit from source and language.
|
||||
|
|
@ -15,21 +15,20 @@ def get_tu(source, lang='c', all_warnings=False):
|
|||
all_warnings is a convenience argument to enable all compiler warnings.
|
||||
"""
|
||||
name = 't.c'
|
||||
args = []
|
||||
if lang == 'cpp':
|
||||
name = 't.cpp'
|
||||
args.append('-std=c++11')
|
||||
elif lang == 'objc':
|
||||
name = 't.m'
|
||||
elif lang != 'c':
|
||||
raise Exception('Unknown language: %s' % lang)
|
||||
|
||||
args = []
|
||||
if all_warnings:
|
||||
args = ['-Wall', '-Wextra']
|
||||
args += ['-Wall', '-Wextra']
|
||||
|
||||
index = Index.create()
|
||||
tu = index.parse(name, args=args, unsaved_files=[(name, source)])
|
||||
assert tu is not None
|
||||
return tu
|
||||
return TranslationUnit.from_source(name, args, unsaved_files=[(name,
|
||||
source)])
|
||||
|
||||
def get_cursor(source, spelling):
|
||||
"""Obtain a cursor from a source object.
|
||||
|
|
@ -57,9 +56,38 @@ def get_cursor(source, spelling):
|
|||
return result
|
||||
|
||||
return None
|
||||
|
||||
def get_cursors(source, spelling):
|
||||
"""Obtain all cursors from a source object with a specific spelling.
|
||||
|
||||
This provides a convenient search mechanism to find all cursors with specific
|
||||
spelling within a source. The first argument can be either a
|
||||
TranslationUnit or Cursor instance.
|
||||
|
||||
If no cursors are found, an empty list is returned.
|
||||
"""
|
||||
cursors = []
|
||||
children = []
|
||||
if isinstance(source, Cursor):
|
||||
children = source.get_children()
|
||||
else:
|
||||
# Assume TU
|
||||
children = source.cursor.get_children()
|
||||
|
||||
for cursor in children:
|
||||
if cursor.spelling == spelling:
|
||||
cursors.append(cursor)
|
||||
|
||||
# Recurse into children.
|
||||
cursors.extend(get_cursors(cursor, spelling))
|
||||
|
||||
return cursors
|
||||
|
||||
|
||||
|
||||
|
||||
__all__ = [
|
||||
'get_cursor',
|
||||
'get_cursors',
|
||||
'get_tu',
|
||||
]
|
||||
|
|
|
|||
434
bindings/xml/comment-xml-schema.rng
Normal file
434
bindings/xml/comment-xml-schema.rng
Normal file
|
|
@ -0,0 +1,434 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<grammar xmlns="http://relaxng.org/ns/structure/1.0"
|
||||
datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
|
||||
|
||||
<start>
|
||||
<choice>
|
||||
<!-- Everything else not explicitly mentioned below. -->
|
||||
<ref name="Other" />
|
||||
|
||||
<ref name="Function" />
|
||||
<ref name="Class" />
|
||||
<ref name="Variable" />
|
||||
<ref name="Namespace" />
|
||||
<ref name="Typedef" />
|
||||
<ref name="Enum" />
|
||||
</choice>
|
||||
</start>
|
||||
|
||||
<define name="Other">
|
||||
<element name="Other">
|
||||
<ref name="attrSourceLocation" />
|
||||
<ref name="Name" />
|
||||
<optional>
|
||||
<ref name="USR" />
|
||||
</optional>
|
||||
<optional>
|
||||
<ref name="Abstract" />
|
||||
</optional>
|
||||
<optional>
|
||||
<ref name="TemplateParameters" />
|
||||
</optional>
|
||||
<optional>
|
||||
<ref name="Parameters" />
|
||||
</optional>
|
||||
<optional>
|
||||
<ref name="ResultDiscussion" />
|
||||
</optional>
|
||||
<optional>
|
||||
<ref name="Discussion" />
|
||||
</optional>
|
||||
</element>
|
||||
</define>
|
||||
|
||||
<define name="Function">
|
||||
<element name="Function">
|
||||
<optional>
|
||||
<attribute name="templateKind">
|
||||
<choice>
|
||||
<value>template</value>
|
||||
<value>specialization</value>
|
||||
</choice>
|
||||
</attribute>
|
||||
</optional>
|
||||
<ref name="attrSourceLocation" />
|
||||
|
||||
<optional>
|
||||
<attribute name="isInstanceMethod">
|
||||
<data type="boolean" />
|
||||
</attribute>
|
||||
</optional>
|
||||
<optional>
|
||||
<attribute name="isClassMethod">
|
||||
<data type="boolean" />
|
||||
</attribute>
|
||||
</optional>
|
||||
|
||||
<ref name="Name" />
|
||||
<optional>
|
||||
<ref name="USR" />
|
||||
</optional>
|
||||
<!-- TODO: Add exception specification. -->
|
||||
<optional>
|
||||
<ref name="Abstract" />
|
||||
</optional>
|
||||
<optional>
|
||||
<ref name="TemplateParameters" />
|
||||
</optional>
|
||||
<optional>
|
||||
<ref name="Parameters" />
|
||||
</optional>
|
||||
<optional>
|
||||
<ref name="ResultDiscussion" />
|
||||
</optional>
|
||||
<optional>
|
||||
<ref name="Discussion" />
|
||||
</optional>
|
||||
</element>
|
||||
</define>
|
||||
|
||||
<define name="Class">
|
||||
<element name="Class">
|
||||
<optional>
|
||||
<attribute name="templateKind">
|
||||
<choice>
|
||||
<value>template</value>
|
||||
<value>specialization</value>
|
||||
<value>partialSpecialization</value>
|
||||
</choice>
|
||||
</attribute>
|
||||
</optional>
|
||||
<ref name="attrSourceLocation" />
|
||||
|
||||
<ref name="Name" />
|
||||
<optional>
|
||||
<ref name="USR" />
|
||||
</optional>
|
||||
<optional>
|
||||
<ref name="Abstract" />
|
||||
</optional>
|
||||
<optional>
|
||||
<ref name="TemplateParameters" />
|
||||
</optional>
|
||||
|
||||
<!-- Parameters and results don't make sense for classes, but the user
|
||||
can specify \param or \returns in a comment anyway. -->
|
||||
<optional>
|
||||
<ref name="Parameters" />
|
||||
</optional>
|
||||
<optional>
|
||||
<ref name="ResultDiscussion" />
|
||||
</optional>
|
||||
|
||||
<optional>
|
||||
<ref name="Discussion" />
|
||||
</optional>
|
||||
</element>
|
||||
</define>
|
||||
|
||||
<define name="Variable">
|
||||
<element name="Variable">
|
||||
<ref name="attrSourceLocation" />
|
||||
<ref name="Name" />
|
||||
<optional>
|
||||
<ref name="USR" />
|
||||
</optional>
|
||||
<optional>
|
||||
<ref name="Abstract" />
|
||||
</optional>
|
||||
|
||||
<!-- Template parameters, parameters and results don't make sense for
|
||||
variables, but the user can specify \tparam \param or \returns
|
||||
in a comment anyway. -->
|
||||
<optional>
|
||||
<ref name="TemplateParameters" />
|
||||
</optional>
|
||||
<optional>
|
||||
<ref name="Parameters" />
|
||||
</optional>
|
||||
<optional>
|
||||
<ref name="ResultDiscussion" />
|
||||
</optional>
|
||||
|
||||
<optional>
|
||||
<ref name="Discussion" />
|
||||
</optional>
|
||||
</element>
|
||||
</define>
|
||||
|
||||
<define name="Namespace">
|
||||
<element name="Namespace">
|
||||
<ref name="attrSourceLocation" />
|
||||
<ref name="Name" />
|
||||
<optional>
|
||||
<ref name="USR" />
|
||||
</optional>
|
||||
<optional>
|
||||
<ref name="Abstract" />
|
||||
</optional>
|
||||
|
||||
<!-- Template parameters, parameters and results don't make sense for
|
||||
namespaces, but the user can specify \tparam, \param or \returns
|
||||
in a comment anyway. -->
|
||||
<optional>
|
||||
<ref name="TemplateParameters" />
|
||||
</optional>
|
||||
<optional>
|
||||
<ref name="Parameters" />
|
||||
</optional>
|
||||
<optional>
|
||||
<ref name="ResultDiscussion" />
|
||||
</optional>
|
||||
|
||||
<optional>
|
||||
<ref name="Discussion" />
|
||||
</optional>
|
||||
</element>
|
||||
</define>
|
||||
|
||||
<define name="Typedef">
|
||||
<element name="Typedef">
|
||||
<ref name="attrSourceLocation" />
|
||||
<ref name="Name" />
|
||||
<optional>
|
||||
<ref name="USR" />
|
||||
</optional>
|
||||
<optional>
|
||||
<ref name="Abstract" />
|
||||
</optional>
|
||||
|
||||
<optional>
|
||||
<ref name="TemplateParameters" />
|
||||
</optional>
|
||||
|
||||
<!-- Parameters and results might make sense for typedefs if the type is
|
||||
a function pointer type. -->
|
||||
<optional>
|
||||
<ref name="Parameters" />
|
||||
</optional>
|
||||
<optional>
|
||||
<ref name="ResultDiscussion" />
|
||||
</optional>
|
||||
|
||||
<optional>
|
||||
<ref name="Discussion" />
|
||||
</optional>
|
||||
</element>
|
||||
</define>
|
||||
|
||||
<define name="Enum">
|
||||
<element name="Enum">
|
||||
<ref name="attrSourceLocation" />
|
||||
<ref name="Name" />
|
||||
<optional>
|
||||
<ref name="USR" />
|
||||
</optional>
|
||||
<optional>
|
||||
<ref name="Abstract" />
|
||||
</optional>
|
||||
|
||||
<!-- Template parameters, parameters and results don't make sense for
|
||||
enums, but the user can specify \tparam \param or \returns in a
|
||||
comment anyway. -->
|
||||
<optional>
|
||||
<ref name="TemplateParameters" />
|
||||
</optional>
|
||||
<optional>
|
||||
<ref name="Parameters" />
|
||||
</optional>
|
||||
<optional>
|
||||
<ref name="ResultDiscussion" />
|
||||
</optional>
|
||||
|
||||
<optional>
|
||||
<ref name="Discussion" />
|
||||
</optional>
|
||||
</element>
|
||||
</define>
|
||||
|
||||
<define name="attrSourceLocation">
|
||||
<optional>
|
||||
<attribute name="file">
|
||||
<!-- Non-empty text content. -->
|
||||
<data type="string">
|
||||
<param name="pattern">.*\S.*</param>
|
||||
</data>
|
||||
</attribute>
|
||||
</optional>
|
||||
<optional>
|
||||
<attribute name="line">
|
||||
<data type="positiveInteger" />
|
||||
</attribute>
|
||||
<attribute name="column">
|
||||
<data type="positiveInteger" />
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
|
||||
<define name="Name">
|
||||
<element name="Name">
|
||||
<!-- Non-empty text content. -->
|
||||
<data type="string">
|
||||
<param name="pattern">.*\S.*</param>
|
||||
</data>
|
||||
</element>
|
||||
</define>
|
||||
|
||||
<define name="USR">
|
||||
<element name="USR">
|
||||
<!-- Non-empty text content. -->
|
||||
<data type="string">
|
||||
<param name="pattern">.*\S.*</param>
|
||||
</data>
|
||||
</element>
|
||||
</define>
|
||||
|
||||
<define name="Abstract">
|
||||
<element name="Abstract">
|
||||
<zeroOrMore>
|
||||
<ref name="TextBlockContent" />
|
||||
</zeroOrMore>
|
||||
</element>
|
||||
</define>
|
||||
|
||||
<define name="Discussion">
|
||||
<element name="Discussion">
|
||||
<oneOrMore>
|
||||
<ref name="TextBlockContent" />
|
||||
</oneOrMore>
|
||||
</element>
|
||||
</define>
|
||||
|
||||
<define name="TemplateParameters">
|
||||
<element name="TemplateParameters">
|
||||
<!-- Parameter elements should be sorted according to position. -->
|
||||
<oneOrMore>
|
||||
<element name="Parameter">
|
||||
<element name="Name">
|
||||
<!-- Non-empty text content. -->
|
||||
<data type="string">
|
||||
<param name="pattern">.*\S.*</param>
|
||||
</data>
|
||||
</element>
|
||||
<optional>
|
||||
<!-- This is index at depth 0. libclang API can return more
|
||||
information about position, but we expose only essential
|
||||
information here, since "Parameter" elements are already
|
||||
sorted.
|
||||
|
||||
"Position" element could be added in future if needed. -->
|
||||
<element name="Index">
|
||||
<data type="nonNegativeInteger" />
|
||||
</element>
|
||||
</optional>
|
||||
<!-- In general, template parameters with whitespace discussion
|
||||
should not be emitted. Schema might be more strict here. -->
|
||||
<element name="Discussion">
|
||||
<ref name="TextBlockContent" />
|
||||
</element>
|
||||
</element>
|
||||
</oneOrMore>
|
||||
</element>
|
||||
</define>
|
||||
|
||||
<define name="Parameters">
|
||||
<element name="Parameters">
|
||||
<!-- Parameter elements should be sorted according to index. -->
|
||||
<oneOrMore>
|
||||
<element name="Parameter">
|
||||
<element name="Name">
|
||||
<!-- Non-empty text content. -->
|
||||
<data type="string">
|
||||
<param name="pattern">.*\S.*</param>
|
||||
</data>
|
||||
</element>
|
||||
<optional>
|
||||
<element name="Index">
|
||||
<data type="nonNegativeInteger" />
|
||||
</element>
|
||||
</optional>
|
||||
<element name="Direction">
|
||||
<attribute name="isExplicit">
|
||||
<data type="boolean" />
|
||||
</attribute>
|
||||
<choice>
|
||||
<value>in</value>
|
||||
<value>out</value>
|
||||
<value>in,out</value>
|
||||
</choice>
|
||||
</element>
|
||||
<!-- In general, template parameters with whitespace discussion
|
||||
should not be emitted, unless direction is explicitly specified.
|
||||
Schema might be more strict here. -->
|
||||
<element name="Discussion">
|
||||
<ref name="TextBlockContent" />
|
||||
</element>
|
||||
</element>
|
||||
</oneOrMore>
|
||||
</element>
|
||||
</define>
|
||||
|
||||
<define name="ResultDiscussion">
|
||||
<element name="ResultDiscussion">
|
||||
<zeroOrMore>
|
||||
<ref name="TextBlockContent" />
|
||||
</zeroOrMore>
|
||||
</element>
|
||||
</define>
|
||||
|
||||
<define name="TextBlockContent">
|
||||
<choice>
|
||||
<element name="Para">
|
||||
<zeroOrMore>
|
||||
<ref name="TextInlineContent" />
|
||||
</zeroOrMore>
|
||||
</element>
|
||||
<element name="Verbatim">
|
||||
<attribute name="xml:space">
|
||||
<value>preserve</value>
|
||||
</attribute>
|
||||
<attribute name="kind">
|
||||
<!-- TODO: add all Doxygen verbatim kinds -->
|
||||
<choice>
|
||||
<value>code</value>
|
||||
<value>verbatim</value>
|
||||
</choice>
|
||||
</attribute>
|
||||
<text />
|
||||
</element>
|
||||
</choice>
|
||||
</define>
|
||||
|
||||
<define name="TextInlineContent">
|
||||
<choice>
|
||||
<text />
|
||||
<element name="bold">
|
||||
<!-- Non-empty text content. -->
|
||||
<data type="string">
|
||||
<param name="pattern">.*\S.*</param>
|
||||
</data>
|
||||
</element>
|
||||
<element name="monospaced">
|
||||
<!-- Non-empty text content. -->
|
||||
<data type="string">
|
||||
<param name="pattern">.*\S.*</param>
|
||||
</data>
|
||||
</element>
|
||||
<element name="emphasized">
|
||||
<!-- Non-empty text content. -->
|
||||
<data type="string">
|
||||
<param name="pattern">.*\S.*</param>
|
||||
</data>
|
||||
</element>
|
||||
<element name="rawHTML">
|
||||
<!-- Non-empty text content. -->
|
||||
<data type="string">
|
||||
<param name="pattern">.*\S.*</param>
|
||||
</data>
|
||||
</element>
|
||||
</choice>
|
||||
</define>
|
||||
|
||||
</grammar>
|
||||
|
||||
|
|
@ -21,14 +21,16 @@
|
|||
|
||||
<h1>AddressSanitizer</h1>
|
||||
<ul>
|
||||
<li> <a href="intro">Introduction</a>
|
||||
<li> <a href="howtobuild">How to Build</a>
|
||||
<li> <a href="usage">Usage</a>
|
||||
<ul><li> <a href="has_feature">__has_feature(address_sanitizer)</a></ul>
|
||||
<li> <a href="platforms">Supported Platforms</a>
|
||||
<li> <a href="limitations">Limitations</a>
|
||||
<li> <a href="status">Current Status</a>
|
||||
<li> <a href="moreinfo">More Information</a>
|
||||
<li> <a href="#intro">Introduction</a>
|
||||
<li> <a href="#howtobuild">How to Build</a>
|
||||
<li> <a href="#usage">Usage</a>
|
||||
<ul><li> <a href="#has_feature">__has_feature(address_sanitizer)</a></ul>
|
||||
<ul><li> <a href="#no_address_safety_analysis">
|
||||
__attribute__((no_address_safety_analysis))</a></ul>
|
||||
<li> <a href="#platforms">Supported Platforms</a>
|
||||
<li> <a href="#limitations">Limitations</a>
|
||||
<li> <a href="#status">Current Status</a>
|
||||
<li> <a href="#moreinfo">More Information</a>
|
||||
</ul>
|
||||
|
||||
<h2 id="intro">Introduction</h2>
|
||||
|
|
@ -97,36 +99,47 @@ AddressSanitizer is enabled.
|
|||
<a href="LanguageExtensions.html#__has_feature_extension">__has_feature</a>
|
||||
can be used for this purpose.
|
||||
<pre>
|
||||
#if defined(__has_feature) && __has_feature(address_sanitizer)
|
||||
code that runs only under AddressSanitizer
|
||||
#else
|
||||
code that does not run under AddressSanitizer
|
||||
#if defined(__has_feature)
|
||||
# if __has_feature(address_sanitizer)
|
||||
code that builds only under AddressSanitizer
|
||||
# endif
|
||||
#endif
|
||||
</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
|
||||
<a href="LanguageExtensions.html#address_sanitizer">
|
||||
<tt>no_address_safety_analysis</tt></a>
|
||||
to disable instrumentation of a particular function.
|
||||
This attribute may not be supported by other compilers, so we suggest to
|
||||
use it together with <tt>__has_feature(address_sanitizer)</tt>.
|
||||
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 i386/x86_64.
|
||||
<li>MacOS 10.6 and 10.7 (i386/x86_64).
|
||||
</ul>
|
||||
Support for Linux i386/ARM and MacOS 10.7 is in progress
|
||||
Support for Linux i386/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.
|
||||
<li> On 64-bit platforms AddressSanitizer maps (but not reserves)
|
||||
16+ Terabytes of virtual address space.
|
||||
This means that tools like <tt>ulimit</tt> may not work as usually expected.
|
||||
<li> Static linking is not supported.
|
||||
<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.
|
||||
<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.
|
||||
This means that tools like <tt>ulimit</tt> may not work as usually expected.
|
||||
<li> Static linking is not supported.
|
||||
</ul>
|
||||
|
||||
|
||||
<h2 id="status">Current Status</h2>
|
||||
AddressSanitizer is fully functional on supported platforms in LLVM head.
|
||||
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).
|
||||
|
||||
|
|
|
|||
|
|
@ -313,7 +313,7 @@ interoperation:</p>
|
|||
<ul>
|
||||
<li>The type system must reliably identify which objects are to be
|
||||
managed. An <tt>int*</tt> might be a pointer to a <tt>malloc</tt>'ed
|
||||
array, or it might be a interior pointer to such an array, or it might
|
||||
array, or it might be an interior pointer to such an array, or it might
|
||||
point to some field or local variable. In contrast, values of the
|
||||
retainable object pointer types are never interior.</li>
|
||||
<li>The type system must reliably indicate how to
|
||||
|
|
@ -1863,7 +1863,7 @@ of these annotations. A program is ill-formed if it annotates the
|
|||
same function with both <tt>cf_audited_transfer</tt>
|
||||
and <tt>cf_unknown_transfer</tt>.</p>
|
||||
|
||||
<p>A pragma is provided to faciliate the mass annotation of interfaces:</p>
|
||||
<p>A pragma is provided to facilitate the mass annotation of interfaces:</p>
|
||||
|
||||
<pre>#pragma arc_cf_code_audited begin
|
||||
...
|
||||
|
|
|
|||
170
docs/ClangPlugins.html
Normal file
170
docs/ClangPlugins.html
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
|
||||
"http://www.w3.org/TR/html4/strict.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Clang Plugins</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>Clang Plugins</h1>
|
||||
<p>Clang Plugins make it possible to run extra user defined actions during
|
||||
a compilation. This document will provide a basic walkthrough of how to write
|
||||
and run a Clang Plugin.</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="intro">Introduction</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>Clang Plugins run FrontendActions over code. See the
|
||||
<a href="RAVFrontendAction.html">FrontendAction tutorial</a> on how to write a
|
||||
FrontendAction using the RecursiveASTVisitor. In this tutorial, we'll
|
||||
demonstrate how to write a simple clang plugin.
|
||||
</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="pluginactions">Writing a PluginASTAction</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>The main difference from writing normal FrontendActions is that you can
|
||||
handle plugin command line options. The
|
||||
PluginASTAction base class declares a ParseArgs method which you have to
|
||||
implement in your plugin.
|
||||
</p>
|
||||
<pre>
|
||||
bool ParseArgs(const CompilerInstance &CI,
|
||||
const std::vector<std::string>& args) {
|
||||
for (unsigned i = 0, e = args.size(); i != e; ++i) {
|
||||
if (args[i] == "-some-arg") {
|
||||
// Handle the command line argument.
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
</pre>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="registerplugin">Registering a plugin</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>A plugin is loaded from a dynamic library at runtime by the compiler. To register
|
||||
a plugin in a library, use FrontendPluginRegistry::Add:</p>
|
||||
<pre>
|
||||
static FrontendPluginRegistry::Add<MyPlugin> X("my-plugin-name", "my plugin description");
|
||||
</pre>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="example">Putting it all together</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>Let's look at an example plugin that prints top-level function names.
|
||||
This example is also checked into the clang repository; please also take a look
|
||||
at the latest <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/examples/PrintFunctionNames/PrintFunctionNames.cpp?view=markup">checked in version of PrintFunctionNames.cpp</a>.</p>
|
||||
<pre>
|
||||
#include "clang/Frontend/FrontendPluginRegistry.h"
|
||||
#include "clang/AST/ASTConsumer.h"
|
||||
#include "clang/AST/AST.h"
|
||||
#include "clang/Frontend/CompilerInstance.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
using namespace clang;
|
||||
|
||||
namespace {
|
||||
|
||||
class PrintFunctionsConsumer : public ASTConsumer {
|
||||
public:
|
||||
virtual bool HandleTopLevelDecl(DeclGroupRef DG) {
|
||||
for (DeclGroupRef::iterator i = DG.begin(), e = DG.end(); i != e; ++i) {
|
||||
const Decl *D = *i;
|
||||
if (const NamedDecl *ND = dyn_cast<NamedDecl>(D))
|
||||
llvm::errs() << "top-level-decl: \"" << ND->getNameAsString() << "\"\n";
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class PrintFunctionNamesAction : public PluginASTAction {
|
||||
protected:
|
||||
ASTConsumer *CreateASTConsumer(CompilerInstance &CI, llvm::StringRef) {
|
||||
return new PrintFunctionsConsumer();
|
||||
}
|
||||
|
||||
bool ParseArgs(const CompilerInstance &CI,
|
||||
const std::vector<std::string>& args) {
|
||||
for (unsigned i = 0, e = args.size(); i != e; ++i) {
|
||||
llvm::errs() << "PrintFunctionNames arg = " << args[i] << "\n";
|
||||
|
||||
// Example error handling.
|
||||
if (args[i] == "-an-error") {
|
||||
DiagnosticsEngine &D = CI.getDiagnostics();
|
||||
unsigned DiagID = D.getCustomDiagID(
|
||||
DiagnosticsEngine::Error, "invalid argument '" + args[i] + "'");
|
||||
D.Report(DiagID);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (args.size() && args[0] == "help")
|
||||
PrintHelp(llvm::errs());
|
||||
|
||||
return true;
|
||||
}
|
||||
void PrintHelp(llvm::raw_ostream& ros) {
|
||||
ros << "Help for PrintFunctionNames plugin goes here\n";
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
static FrontendPluginRegistry::Add<PrintFunctionNamesAction>
|
||||
X("print-fns", "print function names");
|
||||
</pre>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="running">Running the plugin</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>To run a plugin, the dynamic library containing the plugin registry must be
|
||||
loaded via the -load command line option. This will load all plugins that are
|
||||
registered, and you can select the plugins to run by specifying the -plugin
|
||||
option. Additional parameters for the plugins can be passed with -plugin-arg-<plugin-name>.</p>
|
||||
|
||||
<p>Note that those options must reach clang's cc1 process. There are two
|
||||
ways to do so:</p>
|
||||
<ul>
|
||||
<li>
|
||||
Directly call the parsing process by using the -cc1 option; this has the
|
||||
downside of not configuring the default header search paths, so you'll need to
|
||||
specify the full system path configuration on the command line.
|
||||
</li>
|
||||
<li>
|
||||
Use clang as usual, but prefix all arguments to the cc1 process with -Xclang.
|
||||
</li>
|
||||
</ul>
|
||||
<p>For example, to run the print-function-names plugin over a source file in clang,
|
||||
first build the plugin, and then call clang with the plugin from the source tree:</p>
|
||||
<pre>
|
||||
$ export BD=/path/to/build/directory
|
||||
$ (cd $BD && make PrintFunctionNames )
|
||||
$ clang++ -D_GNU_SOURCE -D_DEBUG -D__STDC_CONSTANT_MACROS \
|
||||
-D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -D_GNU_SOURCE \
|
||||
-I$BD/tools/clang/include -Itools/clang/include -I$BD/include -Iinclude \
|
||||
tools/clang/tools/clang-check/ClangCheck.cpp -fsyntax-only \
|
||||
-Xclang -load -Xclang $BD/lib/PrintFunctionNames.so -Xclang \
|
||||
-plugin -Xclang print-fns
|
||||
</pre>
|
||||
|
||||
<p>Also see the print-function-name plugin example's
|
||||
<a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/examples/PrintFunctionNames/README.txt?view=markup">README</a></p>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
118
docs/ClangTools.html
Normal file
118
docs/ClangTools.html
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
|
||||
"http://www.w3.org/TR/html4/strict.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Clang Tools</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>Clang Tools</h1>
|
||||
<p>Clang Tools are standalone command line (and potentially GUI) tools design
|
||||
for use by C++ developers who are already using and enjoying Clang as their
|
||||
compiler. These tools provide developer-oriented functionality such as fast
|
||||
syntax checking, automatic formatting, refactoring, etc.</p>
|
||||
|
||||
<p>Only a couple of the most basic and fundamental tools are kept in the primary
|
||||
Clang Subversion project. The rest of the tools are kept in a side-project so
|
||||
that developers who don't want or need to build them don't. If you want to get
|
||||
access to the extra Clang Tools repository, simply check it out into the tools
|
||||
tree of your Clang checkout and follow the usual process for building and
|
||||
working with a combined LLVM/Clang checkout:</p>
|
||||
<ul>
|
||||
<li>With Subversion:
|
||||
<ul>
|
||||
<li><tt>cd llvm/tools/clang/tools</tt></li>
|
||||
<li><tt>svn co http://llvm.org/svn/llvm-project/clang-tools-extra/trunk
|
||||
extra</tt></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Or with Git:
|
||||
<ul>
|
||||
<li><tt>cd llvm/tools/clang/tools</tt></li>
|
||||
<li><tt>git clone http://llvm.org/git/clang-tools-extra.git extra</tt></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>This document describes a high-level overview of the organization of Clang
|
||||
Tools within the project as well as giving an introduction to some of the more
|
||||
important tools. However, it should be noted that this document is currently
|
||||
focused on Clang and Clang Tool developers, not on end users of these tools.</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="org">Clang Tools Organization</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>Clang Tools are CLI or GUI programs that are intended to be directly used by
|
||||
C++ developers. That is they are <em>not</em> primarily for use by Clang
|
||||
developers, although they are hopefully useful to C++ developers who happen to
|
||||
work on Clang, and we try to actively dogfood their functionality. They are
|
||||
developed in three components: the underlying infrastructure for building
|
||||
a standalone tool based on Clang, core shared logic used by many different tools
|
||||
in the form of refactoring and rewriting libraries, and the tools
|
||||
themselves.</p>
|
||||
|
||||
<p>The underlying infrastructure for Clang Tools is the
|
||||
<a href="LibTooling.html">LibTooling</a> platform. See its documentation for
|
||||
much more detailed information about how this infrastructure works. The common
|
||||
refactoring and rewriting toolkit-style library is also part of LibTooling
|
||||
organizationally.</p>
|
||||
|
||||
<p>A few Clang Tools are developed along side the core Clang libraries as
|
||||
examples and test cases of fundamental functionality. However, most of the tools
|
||||
are developed in a side repository to provide easy separation from the core
|
||||
libraries. We intentionally do not support public libraries in the side
|
||||
repository, as we want to carefully review and find good APIs for libraries as
|
||||
they are lifted out of a few tools and into the core Clang library set.</p>
|
||||
|
||||
<p>Regardless of which repository Clang Tools' code resides in, the development
|
||||
process and practices for all Clang Tools are exactly those of Clang itself.
|
||||
They are entirely within the Clang <em>project</em>, regardless of the version
|
||||
control scheme.</p>
|
||||
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="coretools">Core Clang Tools</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>The core set of Clang tools that are within the main repository are tools
|
||||
that very specifically compliment, and allow use and testing of <em>Clang</em>
|
||||
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>
|
||||
|
||||
<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>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>As various categories of Clang Tools are added to the extra repository,
|
||||
they'll be tracked here. The focus of this documentation is on the scope and
|
||||
features of the tools for other tool developers; each tool should provide its
|
||||
own user-focused documentation.</p>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
186
docs/HowToSetupToolingForLLVM.html
Normal file
186
docs/HowToSetupToolingForLLVM.html
Normal file
|
|
@ -0,0 +1,186 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
|
||||
"http://www.w3.org/TR/html4/strict.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>How To Setup Clang Tooling For LLVM</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>How To Setup Clang Tooling For LLVM</h1>
|
||||
<p>Clang Tooling provides infrastructure to write tools that need syntactic and
|
||||
semantic infomation about a program. This term also relates to a set of specific
|
||||
tools using this infrastructure (e.g. <code>clang-check</code>). This document
|
||||
provides information on how to set up and use Clang Tooling for the LLVM source
|
||||
code.</p>
|
||||
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2><a name="introduction">Introduction</a></h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>Clang Tooling needs a compilation database to figure out specific build
|
||||
options for each file. Currently it can create a compilation database from the
|
||||
<code>compilation_commands.json</code> file, generated by CMake. When invoking
|
||||
clang tools, you can either specify a path to a build directory using a command
|
||||
line parameter <code>-p</code> or let Clang Tooling find this file in your
|
||||
source tree. In either case you need to configure your build using CMake to use
|
||||
clang tools.</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2><a name="using-make">Setup Clang Tooling Using CMake and Make</a></h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>If you intend to use make to build LLVM, you should have CMake 2.8.6 or later
|
||||
installed (can be found <a href="http://cmake.org">here</a>).</p>
|
||||
<p>First, you need to generate Makefiles for LLVM with CMake. You need to make
|
||||
a build directory and run CMake from it:</p>
|
||||
<pre>
|
||||
mkdir your/build/directory
|
||||
cd your/build/directory
|
||||
cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON path/to/llvm/sources
|
||||
</pre>
|
||||
|
||||
<p>If you want to use clang instead of GCC, you can add
|
||||
<code>-DCMAKE_C_COMPILER=/path/to/clang
|
||||
-DCMAKE_CXX_COMPILER=/path/to/clang++</code>.
|
||||
You can also use ccmake, which provides a curses interface to configure CMake
|
||||
variables for lazy people.</p>
|
||||
|
||||
<p>As a result, the new <code>compile_commands.json</code> file should appear in
|
||||
the current directory. You should link it to the LLVM source tree so that Clang
|
||||
Tooling is able to use it:</p>
|
||||
<pre>
|
||||
ln -s $PWD/compile_commands.json path/to/llvm/source/
|
||||
</pre>
|
||||
|
||||
<p>Now you are ready to build and test LLVM using make:</p>
|
||||
<pre>
|
||||
make check-all
|
||||
</pre>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2><a name="using-tools">Using Clang Tools</a></h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>After you completed the previous steps, you are ready to run clang tools. If
|
||||
you have a recent clang installed, you should have <code>clang-check</code> in
|
||||
$PATH. Try to run it on any .cpp file inside the LLVM source tree:</p>
|
||||
<pre>
|
||||
clang-check tools/clang/lib/Tooling/CompilationDatabase.cpp
|
||||
</pre>
|
||||
<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>
|
||||
</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>Other <code>clang-check</code> options that can be useful when working with
|
||||
clang AST:</p>
|
||||
<ul>
|
||||
<li><code>-ast-print</code> - Build ASTs and then pretty-print them.</li>
|
||||
<li><code>-ast-dump</code> - Build ASTs and then debug dump them.</li>
|
||||
<li><code>-ast-dump-filter=<string></code> - Use with
|
||||
<code>-ast-dump</code> or <code>-ast-print</code> to dump/print
|
||||
only AST declaration nodes having a certain substring in a qualified name.
|
||||
Use <code>-ast-list</code> to list all filterable declaration node
|
||||
names.</li>
|
||||
<li><code>-ast-list</code> - Build ASTs and print the list of declaration
|
||||
node qualified names.</li>
|
||||
</ul>
|
||||
<p>Examples:</p>
|
||||
<pre>
|
||||
<b>$ clang-check tools/clang/tools/clang-check/ClangCheck.cpp -ast-dump -ast-dump-filter ActionFactory::newASTConsumer</b>
|
||||
Processing: tools/clang/tools/clang-check/ClangCheck.cpp.
|
||||
Dumping <anonymous namespace>::ActionFactory::newASTConsumer:
|
||||
clang::ASTConsumer *newASTConsumer() (CompoundStmt 0x44da290 </home/alexfh/local/llvm/tools/clang/tools/clang-check/ClangCheck.cpp:64:40, line:72:3>
|
||||
(IfStmt 0x44d97c8 <line:65:5, line:66:45>
|
||||
<<<NULL>>>
|
||||
(ImplicitCastExpr 0x44d96d0 <line:65:9> '_Bool':'_Bool' <UserDefinedConversion>
|
||||
...
|
||||
<b>$ clang-check tools/clang/tools/clang-check/ClangCheck.cpp -ast-print -ast-dump-filter ActionFactory::newASTConsumer</b>
|
||||
Processing: tools/clang/tools/clang-check/ClangCheck.cpp.
|
||||
Printing <anonymous namespace>::ActionFactory::newASTConsumer:
|
||||
clang::ASTConsumer *newASTConsumer() {
|
||||
if (this->ASTList.operator _Bool())
|
||||
return clang::CreateASTDeclNodeLister();
|
||||
if (this->ASTDump.operator _Bool())
|
||||
return clang::CreateASTDumper(this->ASTDumpFilter);
|
||||
if (this->ASTPrint.operator _Bool())
|
||||
return clang::CreateASTPrinter(&llvm::outs(), this->ASTDumpFilter);
|
||||
return new clang::ASTConsumer();
|
||||
}
|
||||
</pre>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2><a name="using-ninja">(Experimental) Using Ninja Build System</a></h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>Optionally you can use the <a
|
||||
href="https://github.com/martine/ninja">Ninja</a> build system instead of
|
||||
make. It is aimed at making your builds faster. Currently this step will require
|
||||
building Ninja from sources and using a development version of CMake.</p>
|
||||
<p>To take advantage of using Clang Tools along with Ninja build you need at
|
||||
least CMake 2.8.9. At the moment CMake 2.8.9 is still under development, so you
|
||||
can get latest development sources and build it yourself:</p>
|
||||
<pre>
|
||||
git clone git://cmake.org/cmake.git
|
||||
cd cmake
|
||||
./bootstrap
|
||||
make
|
||||
sudo make install
|
||||
</pre>
|
||||
|
||||
<p>Having the correct version of CMake, you can clone the Ninja git repository
|
||||
and build Ninja from sources:</p>
|
||||
<pre>
|
||||
git clone git://github.com/martine/ninja.git
|
||||
cd ninja/
|
||||
./bootstrap.py
|
||||
</pre>
|
||||
<p>This will result in a single binary <code>ninja</code> in the current
|
||||
directory. It doesn't require installation and can just be copied to any
|
||||
location inside <code>$PATH</code>, say <code>/usr/local/bin/</code>:</p>
|
||||
<pre>
|
||||
sudo cp ninja /usr/local/bin/
|
||||
sudo chmod a+rx /usr/local/bin/ninja
|
||||
</pre>
|
||||
<p>After doing all of this, you'll need to generate Ninja build files for LLVM
|
||||
with CMake. You need to make a build directory and run CMake from it:</p>
|
||||
<pre>
|
||||
mkdir your/build/directory
|
||||
cd your/build/directory
|
||||
cmake -G Ninja -DCMAKE_EXPORT_COMPILE_COMMANDS=ON path/to/llvm/sources
|
||||
</pre>
|
||||
|
||||
<p>If you want to use clang instead of GCC, you can add
|
||||
<code>-DCMAKE_C_COMPILER=/path/to/clang
|
||||
-DCMAKE_CXX_COMPILER=/path/to/clang++</code>.
|
||||
You can also use ccmake, which provides a curses interface to configure CMake
|
||||
variables in an interactive manner.</p>
|
||||
|
||||
<p>As a result, the new <code>compile_commands.json</code> file should appear in
|
||||
the current directory. You should link it to the LLVM source tree so that Clang
|
||||
Tooling is able to use it:</p>
|
||||
<pre>
|
||||
ln -s $PWD/compile_commands.json path/to/llvm/source/
|
||||
</pre>
|
||||
|
||||
<p>Now you are ready to build and test LLVM using Ninja:</p>
|
||||
<pre>
|
||||
ninja check-all
|
||||
</pre>
|
||||
<p>Other target names can be used in the same way as with make.</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
|
@ -357,6 +357,12 @@ Clang:</p>
|
|||
<tr><td>Example:</td><td><tt>"candidate found by name lookup is %q0"</tt></td></tr>
|
||||
<tr><td>Class:</td><td>NamedDecl*</td></tr>
|
||||
<tr><td>Description</td><td><p>This formatter indicates that the fully-qualified name of the declaration should be printed, e.g., "std::vector" rather than "vector".</p></td></tr>
|
||||
|
||||
<tr><td colspan="2"><b>"diff" format</b></td></tr>
|
||||
<tr><td>Example:</td><td><tt>"no known conversion %diff{from | to | }1,2"</tt></td></tr>
|
||||
<tr><td>Class:</td><td>QualType</td></tr>
|
||||
<tr><td>Description</td><td><p>This formatter takes two QualTypes and attempts to print a template difference between the two. If tree printing is off, the text inside the braces before the pipe is printed, with the formatted text replacing the $. If tree printing is on, the text after the pipe is printed and a type tree is printed after the diagnostic message.
|
||||
</p></td></tr>
|
||||
|
||||
</table>
|
||||
|
||||
|
|
@ -441,6 +447,18 @@ href="#DiagnosticClient">Other diagnostic clients</a> might choose
|
|||
to render the code differently (e.g., as markup inline) or even give
|
||||
the user the ability to automatically fix the problem.</p>
|
||||
|
||||
<p>Fix-it hints on errors and warnings need to obey these rules:</p>
|
||||
|
||||
<ul>
|
||||
<li>Since they are automatically applied if <code>-Xclang -fixit</code>
|
||||
is passed to the driver, they should only be used when it's very likely they
|
||||
match the user's intent.</li>
|
||||
<li>Clang must recover from errors as if the fix-it had been applied.</li>
|
||||
</ul>
|
||||
|
||||
<p>If a fix-it can't obey these rules, put the fix-it on a note. Fix-its on
|
||||
notes are not applied automatically.</p>
|
||||
|
||||
<p>All fix-it hints are described by the <code>FixItHint</code> class,
|
||||
instances of which should be attached to the diagnostic using the
|
||||
<< operator in the same way that highlighted source ranges and
|
||||
|
|
@ -1686,7 +1704,7 @@ interacts with constant evaluation:</p>
|
|||
<li><b><tt>__extension__</tt></b>: The expression form of this extension causes
|
||||
any evaluatable subexpression to be accepted as an integer constant
|
||||
expression.</li>
|
||||
<li><b><tt>__builtin_constant_p</tt></b>: This returns true (as a integer
|
||||
<li><b><tt>__builtin_constant_p</tt></b>: This returns true (as an integer
|
||||
constant expression) if the operand evaluates to either a numeric value
|
||||
(that is, not a pointer cast to integral type) of integral, enumeration,
|
||||
floating or complex type, or if it evaluates to the address of the first
|
||||
|
|
@ -1751,18 +1769,6 @@ then <tt>__attribute__((myattribute("Hello", 3)))</tt> will be a valid use.</p>
|
|||
|
||||
<h4>Boilerplate</h4>
|
||||
|
||||
<p>Add an element to the <tt>AttributeList::Kind</tt> enum in <a
|
||||
href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/AttributeList.h?view=markup">include/clang/Sema/AttributeList.h</a>
|
||||
named <tt>AT_lower_with_underscores</tt>. That is, a CamelCased
|
||||
<tt>AttributeName</tt> in <tt>Attr.td</tt> name should become
|
||||
<tt>AT_attribute_name</tt>.</p>
|
||||
|
||||
<p>Add a case to the <tt>StringSwitch</tt> in <tt>AttributeList::getKind()</tt>
|
||||
in <a
|
||||
href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/AttributeList.cpp?view=markup">lib/Sema/AttributeList.cpp</a>
|
||||
for each spelling of your attribute. Less common attributes should come toward
|
||||
the end of that list.</p>
|
||||
|
||||
<p>Write a new <tt>HandleYourAttr()</tt> function in <a
|
||||
href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?view=markup">lib/Sema/SemaDeclAttr.cpp</a>,
|
||||
and add a case to the switch in <tt>ProcessNonInheritableDeclAttr()</tt> or
|
||||
|
|
|
|||
139
docs/IntroductionToTheClangAST.html
Normal file
139
docs/IntroductionToTheClangAST.html
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
|
||||
"http://www.w3.org/TR/html4/strict.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Introduction to 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>Introduction to the Clang AST</h1>
|
||||
<p>This document gives a gentle introduction to the mysteries of the Clang AST.
|
||||
It is targeted at developers who either want to contribute to Clang, or use
|
||||
tools that work based on Clang's AST, like the AST matchers.</p>
|
||||
<!-- FIXME: Add link once we have an AST matcher document -->
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="intro">Introduction</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>Clang's AST is different from ASTs produced by some other compilers in that it closely
|
||||
resembles both the written C++ code and the C++ standard. For example,
|
||||
parenthesis expressions and compile time constants are available in an unreduced
|
||||
form in the AST. This makes Clang's AST a good fit for refactoring tools.</p>
|
||||
|
||||
<p>Documentation for all Clang AST nodes is available via the generated
|
||||
<a href="http://clang.llvm.org/doxygen">Doxygen</a>. The doxygen online
|
||||
documentation is also indexed by your favorite search engine, which will make
|
||||
a search for clang and the AST node's class name usually turn up the doxygen
|
||||
of the class you're looking for (for example, search for: clang ParenExpr).</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="examine">Examining the AST</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>A good way to familarize yourself with the Clang AST is to actually look
|
||||
at it on some simple example code. Clang has a builtin AST-dump modes, which
|
||||
can be enabled with the flags -ast-dump and -ast-dump-xml. Note that -ast-dump-xml
|
||||
currently only works with debug-builds of clang.</p>
|
||||
|
||||
<p>Let's look at a simple example AST:</p>
|
||||
<pre>
|
||||
# cat test.cc
|
||||
int f(int x) {
|
||||
int result = (x / 42);
|
||||
return result;
|
||||
}
|
||||
|
||||
# Clang by default is a frontend for many tools; -cc1 tells it to directly
|
||||
# use the C++ compiler mode. -undef leaves out some internal declarations.
|
||||
$ clang -cc1 -undef -ast-dump-xml test.cc
|
||||
... cutting out internal declarations of clang ...
|
||||
<TranslationUnit ptr="0x4871160">
|
||||
<Function ptr="0x48a5800" name="f" prototype="true">
|
||||
<FunctionProtoType ptr="0x4871de0" canonical="0x4871de0">
|
||||
<BuiltinType ptr="0x4871250" canonical="0x4871250"/>
|
||||
<parameters>
|
||||
<BuiltinType ptr="0x4871250" canonical="0x4871250"/>
|
||||
</parameters>
|
||||
</FunctionProtoType>
|
||||
<ParmVar ptr="0x4871d80" name="x" initstyle="c">
|
||||
<BuiltinType ptr="0x4871250" canonical="0x4871250"/>
|
||||
</ParmVar>
|
||||
<Stmt>
|
||||
(CompoundStmt 0x48a5a38 <t2.cc:1:14, line:4:1>
|
||||
(DeclStmt 0x48a59c0 <line:2:3, col:24>
|
||||
0x48a58c0 "int result =
|
||||
(ParenExpr 0x48a59a0 <col:16, col:23> 'int'
|
||||
(BinaryOperator 0x48a5978 <col:17, col:21> 'int' '/'
|
||||
(ImplicitCastExpr 0x48a5960 <col:17> 'int' <LValueToRValue>
|
||||
(DeclRefExpr 0x48a5918 <col:17> 'int' lvalue ParmVar 0x4871d80 'x' 'int'))
|
||||
(IntegerLiteral 0x48a5940 <col:21> 'int' 42)))")
|
||||
(ReturnStmt 0x48a5a18 <line:3:3, col:10>
|
||||
(ImplicitCastExpr 0x48a5a00 <col:10> 'int' <LValueToRValue>
|
||||
(DeclRefExpr 0x48a59d8 <col:10> 'int' lvalue Var 0x48a58c0 'result' 'int'))))
|
||||
|
||||
</Stmt>
|
||||
</Function>
|
||||
</TranslationUnit>
|
||||
</pre>
|
||||
<p>In general, -ast-dump-xml dumps declarations in an XML-style format and
|
||||
statements in an S-expression-style format.
|
||||
The toplevel declaration in a translation unit is always the
|
||||
<a href="http://clang.llvm.org/doxygen/classclang_1_1TranslationUnitDecl.html">translation unit declaration</a>.
|
||||
In this example, our first user written declaration is the
|
||||
<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">function declaration</a>
|
||||
of 'f'. The body of 'f' is a <a href="http://clang.llvm.org/doxygen/classclang_1_1CompoundStmt.html">compound statement</a>,
|
||||
whose child nodes are a <a href="http://clang.llvm.org/doxygen/classclang_1_1DeclStmt.html">declaration statement</a>
|
||||
that declares our result variable, and the
|
||||
<a href="http://clang.llvm.org/doxygen/classclang_1_1ReturnStmt.html">return statement</a>.</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="context">AST Context</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>All information about the AST for a translation unit is bundled up in the class
|
||||
<a href="http://clang.llvm.org/doxygen/classclang_1_1ASTContext.html">ASTContext</a>.
|
||||
It allows traversal of the whole translation unit starting from
|
||||
<a href="http://clang.llvm.org/doxygen/classclang_1_1ASTContext.html#abd909fb01ef10cfd0244832a67b1dd64">getTranslationUnitDecl</a>,
|
||||
or to access Clang's <a href="http://clang.llvm.org/doxygen/classclang_1_1ASTContext.html#a4f95adb9958e22fbe55212ae6482feb4">table of identifiers</a>
|
||||
for the parsed translation unit.</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="nodes">AST Nodes</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>Clang's AST nodes are modeled on a class hierarchy that does not have a common
|
||||
ancestor. Instead, there are multiple larger hierarchies for basic node types like
|
||||
<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a> and
|
||||
<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>. Many
|
||||
important AST nodes derive from <a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>,
|
||||
<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>,
|
||||
<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclContext.html">DeclContext</a> or
|
||||
<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>,
|
||||
with some classes deriving from both Decl and DeclContext.</p>
|
||||
<p>There are also a multitude of nodes in the AST that are not part of a
|
||||
larger hierarchy, and are only reachable from specific other nodes,
|
||||
like <a href="http://clang.llvm.org/doxygen/classclang_1_1CXXBaseSpecifier.html">CXXBaseSpecifier</a>.
|
||||
</p>
|
||||
|
||||
<p>Thus, to traverse the full AST, one starts from the <a href="http://clang.llvm.org/doxygen/classclang_1_1TranslationUnitDecl.html">TranslationUnitDecl</a>
|
||||
and then recursively traverses everything that can be reached from that node
|
||||
- this information has to be encoded for each specific node type. This algorithm
|
||||
is encoded in the <a href="http://clang.llvm.org/doxygen/classclang_1_1RecursiveASTVisitor.html">RecursiveASTVisitor</a>.
|
||||
See the <a href="http://clang.llvm.org/docs/RAVFrontendAction.html">RecursiveASTVisitor tutorial</a>.</p>
|
||||
|
||||
<p>The two most basic nodes in the Clang AST are statements (<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>)
|
||||
and declarations (<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>).
|
||||
Note that expressions (<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>)
|
||||
are also statements in Clang's AST.</p>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
89
docs/JSONCompilationDatabase.html
Normal file
89
docs/JSONCompilationDatabase.html
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
|
||||
"http://www.w3.org/TR/html4/strict.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>JSON Compilation Database Format Specification</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>JSON Compilation Database Format Specification</h1>
|
||||
<p>This document describes a format for specifying how to replay
|
||||
single compilations independently of the build system.</p>
|
||||
|
||||
<h2>Background</h2>
|
||||
<p>Tools based on the C++ Abstract Syntax Tree need full information how to
|
||||
parse a translation unit. Usually this information is implicitly
|
||||
available in the build system, but running tools as part of
|
||||
the build system is not necessarily the best solution:
|
||||
<ul>
|
||||
<li>Build systems are inherently change driven, so running multiple
|
||||
tools over the same code base without changing the code does not fit
|
||||
into the architecture of many build systems.</li>
|
||||
<li>Figuring out whether things have changed is often an IO bound
|
||||
process; this makes it hard to build low latency end user tools based
|
||||
on the build system.</li>
|
||||
<li>Build systems are inherently sequential in the build graph, for example
|
||||
due to generated source code. While tools that run independently of the
|
||||
build still need the generated source code to exist, running tools multiple
|
||||
times over unchanging source does not require serialization of the runs
|
||||
according to the build dependency graph.</li>
|
||||
</ul>
|
||||
</p>
|
||||
|
||||
<h2>Supported Systems</h2>
|
||||
<p>Currently <a href="http://cmake.org">CMake</a> (since 2.8.5) supports generation of compilation
|
||||
databases for Unix Makefile builds (Ninja builds in the works) with the option
|
||||
CMAKE_EXPORT_COMPILE_COMMANDS.</p>
|
||||
<p>Clang's tooling interface supports reading compilation databases; see
|
||||
the <a href="LibTooling.html">LibTooling documentation</a>. libclang and its
|
||||
python bindings also support this (since clang 3.2); see
|
||||
<a href="/doxygen/group__COMPILATIONDB.html">CXCompilationDatabase.h</a>.</p>
|
||||
|
||||
<h2>Format</h2>
|
||||
<p>A compilation database is a JSON file, which consist of an array of
|
||||
"command objects", where each command object specifies one way a translation unit
|
||||
is compiled in the project.</p>
|
||||
<p>Each command object contains the translation unit's main file, the working
|
||||
directory of the compile run and the actual compile command.</p>
|
||||
<p>Example:
|
||||
<pre>
|
||||
[
|
||||
{ "directory": "/home/user/llvm/build",
|
||||
"command": "/usr/bin/clang++ -Irelative -DSOMEDEF='\"With spaces and quotes.\"' -c -o file.o file.cc",
|
||||
"file": "file.cc" },
|
||||
...
|
||||
]
|
||||
</pre>
|
||||
The contracts for each field in the command object are:
|
||||
<ul>
|
||||
<li><b>directory:</b> The working directory of the compilation. All paths specified
|
||||
in the <b>command</b> or <b>file</b> fields must be either absolute or relative to
|
||||
this directory.</li>
|
||||
<li><b>file:</b> The main translation unit source processed by this compilation step.
|
||||
This is used by tools as the key into the compilation database. There can be multiple
|
||||
command objects for the same file, for example if the same source file is
|
||||
compiled with different configurations.</li>
|
||||
<li><b>command:</b> The compile command executed. After JSON unescaping, this must
|
||||
be a valid command to rerun the exact compilation step for the translation unit in
|
||||
the environment the build system uses. Parameters use shell quoting and shell escaping
|
||||
of quotes, with '"' and '\' being the only special characters. Shell expansion is
|
||||
not supported.</li>
|
||||
</ul>
|
||||
</p>
|
||||
|
||||
<h2>Build System Integration</h2>
|
||||
<p>The convention is to name the file compile_commands.json and put it at the top
|
||||
of the build directory. Clang tools are pointed to the top of the build directory
|
||||
to detect the file and use the compilation database to parse C++ code in the source
|
||||
tree.</p>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
|
@ -91,18 +91,24 @@
|
|||
<li><a href="#objc_arc">Automatic reference counting</a></li>
|
||||
<li><a href="#objc_fixed_enum">Enumerations with a fixed underlying type</a></li>
|
||||
<li><a href="#objc_lambdas">Interoperability with C++11 lambdas</a></li>
|
||||
<li><a href="#object-literals-subscripting">Object Literals and Subscripting</a></li>
|
||||
<li><a href="#objc_object_literals_subscripting">Object Literals and Subscripting</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#overloading-in-c">Function Overloading in C</a></li>
|
||||
<li><a href="#complex-list-init">Initializer lists for complex numbers in C</a></li>
|
||||
<li><a href="#builtins">Builtin Functions</a>
|
||||
<ul>
|
||||
<li><a href="#__builtin_readcyclecounter">__builtin_readcyclecounter</a></li>
|
||||
<li><a href="#__builtin_shufflevector">__builtin_shufflevector</a></li>
|
||||
<li><a href="#__builtin_unreachable">__builtin_unreachable</a></li>
|
||||
<li><a href="#__sync_swap">__sync_swap</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#non-standard-attributes">Non-standard C++11 Attributes</a>
|
||||
<ul>
|
||||
<li><a href="#clang__fallthrough">The <tt>clang::fallthrough</tt> attribute</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#targetspecific">Target-Specific Extensions</a>
|
||||
<ul>
|
||||
<li><a href="#x86-specific">X86/X86-64 Language Extensions</a></li>
|
||||
|
|
@ -655,7 +661,7 @@ framework search path. For consistency, we recommend that such files never be
|
|||
included in installed versions of the framework.</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="availability">Availability attribute</h2
|
||||
<h2 id="availability">Availability attribute</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>Clang introduces the <code>availability</code> attribute, which can
|
||||
|
|
@ -937,8 +943,8 @@ is enabled.</p>
|
|||
<p>Use <tt>__has_feature(c_atomic)</tt> or <tt>__has_extension(c_atomic)</tt>
|
||||
to determine if support for atomic types using <tt>_Atomic</tt> is enabled.
|
||||
Clang also provides <a href="#__c11_atomic">a set of builtins</a> which can be
|
||||
used to implement the <tt><stdatomic.h></tt> operations on _Atomic
|
||||
types.</p>
|
||||
used to implement the <tt><stdatomic.h></tt> operations on
|
||||
<tt>_Atomic</tt> types.</p>
|
||||
|
||||
<h4 id="c_generic_selections">C11 generic selections</h4>
|
||||
|
||||
|
|
@ -1183,10 +1189,28 @@ in Objective-C++, and not in C++ with blocks, due to its use of
|
|||
Objective-C memory management (autorelease).</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="object-literals-subscripting">Object Literals and Subscripting</h2>
|
||||
<h2 id="objc_object_literals_subscripting">Object Literals and Subscripting</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>Clang provides support for <a href="ObjectiveCLiterals.html">Object Literals and Subscripting</a> in Objective-C, which simplifies common Objective-C programming patterns, makes programs more concise, and improves the safety of container creation. There are several feature macros associated with object literals and subscripting: <code>__has_feature(objc_array_literals)</code> tests the availability of array literals; <code>__has_feature(objc_dictionary_literals)</code> tests the availability of dictionary literals; <code>__has_feature(objc_subscripting)</code> tests the availability of object subscripting.</p>
|
||||
<p>Clang provides support for <a href="ObjectiveCLiterals.html">Object Literals
|
||||
and Subscripting</a> in Objective-C, which simplifies common Objective-C
|
||||
programming patterns, makes programs more concise, and improves the safety of
|
||||
container creation. There are several feature macros associated with object
|
||||
literals and subscripting: <code>__has_feature(objc_array_literals)</code>
|
||||
tests the availability of array literals;
|
||||
<code>__has_feature(objc_dictionary_literals)</code> tests the availability of
|
||||
dictionary literals; <code>__has_feature(objc_subscripting)</code> tests the
|
||||
availability of object subscripting.</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="objc_default_synthesize_properties">Objective-C Autosynthesis of Properties</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p> Clang provides support for autosynthesis of declared properties. Using this
|
||||
feature, clang provides default synthesis of those properties not declared @dynamic
|
||||
and not having user provided backing getter and setter methods.
|
||||
<code>__has_feature(objc_default_synthesize_properties)</code> checks for availability
|
||||
of this feature in version of clang being used.</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="overloading-in-c">Function Overloading in C</h2>
|
||||
|
|
@ -1343,6 +1367,42 @@ functions are implemented directly in terms of <a href="#vectors">extended
|
|||
vector support</a> instead of builtins, in order to reduce the number of
|
||||
builtins that we need to implement.</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h3><a name="__builtin_readcyclecounter">__builtin_readcyclecounter</a></h3>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p><tt>__builtin_readcyclecounter</tt> is used to access the cycle counter
|
||||
register (or a similar low-latency, high-accuracy clock) on those targets that
|
||||
support it.
|
||||
</p>
|
||||
|
||||
<p><b>Syntax:</b></p>
|
||||
|
||||
<pre>
|
||||
__builtin_readcyclecounter()
|
||||
</pre>
|
||||
|
||||
<p><b>Example of Use:</b></p>
|
||||
|
||||
<pre>
|
||||
unsigned long long t0 = __builtin_readcyclecounter();
|
||||
do_something();
|
||||
unsigned long long t1 = __builtin_readcyclecounter();
|
||||
unsigned long long cycles_to_do_something = t1 - t0; // assuming no overflow
|
||||
</pre>
|
||||
|
||||
<p><b>Description:</b></p>
|
||||
|
||||
<p>The __builtin_readcyclecounter() builtin returns the cycle counter value,
|
||||
which may be either global or process/thread-specific depending on the target.
|
||||
As the backing counters often overflow quickly (on the order of
|
||||
seconds) this should only be used for timing small intervals. When not
|
||||
supported by the target, the return value is always zero. This builtin
|
||||
takes no arguments and produces an unsigned long long result.
|
||||
</p>
|
||||
|
||||
<p>Query for this feature with __has_builtin(__builtin_readcyclecounter).</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h3><a name="__builtin_shufflevector">__builtin_shufflevector</a></h3>
|
||||
<!-- ======================================================================= -->
|
||||
|
|
@ -1489,6 +1549,54 @@ with a <tt>__c11_</tt> prefix. The supported operations are:</p>
|
|||
<li><tt>__c11_atomic_fetch_xor</tt></li>
|
||||
</ul>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="non-standard-attributes">Non-standard C++11 Attributes</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>Clang supports one non-standard C++11 attribute. It resides in the
|
||||
<tt>clang</tt> attribute namespace.</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h3 id="clang__fallthrough">The <tt>clang::fallthrough</tt> attribute</h3>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>The <tt>clang::fallthrough</tt> attribute is used along with the
|
||||
<tt>-Wimplicit-fallthrough</tt> argument to annotate intentional fall-through
|
||||
between switch labels. It can only be applied to a null statement placed at a
|
||||
point of execution between any statement and the next switch label. It is common
|
||||
to mark these places with a specific comment, but this attribute is meant to
|
||||
replace comments with a more strict annotation, which can be checked by the
|
||||
compiler. This attribute doesn't change semantics of the code and can be used
|
||||
wherever an intended fall-through occurs. It is designed to mimic
|
||||
control-flow statements like <tt>break;</tt>, so it can be placed in most places
|
||||
where <tt>break;</tt> can, but only if there are no statements on the execution
|
||||
path between it and the next switch label.</p>
|
||||
<p>Here is an example:</p>
|
||||
<pre>
|
||||
// compile with -Wimplicit-fallthrough
|
||||
switch (n) {
|
||||
case 33:
|
||||
f();
|
||||
case 44: // warning: unannotated fall-through
|
||||
g();
|
||||
<b>[[clang::fallthrough]];</b>
|
||||
case 55: // no warning
|
||||
if (x) {
|
||||
h();
|
||||
break;
|
||||
}
|
||||
else {
|
||||
i();
|
||||
<b>[[clang::fallthrough]];</b>
|
||||
}
|
||||
case 66: // no warning
|
||||
p();
|
||||
<b>[[clang::fallthrough]];</b> // warning: fallthrough annotation does not directly precede case label
|
||||
q();
|
||||
case 77: // warning: unannotated fall-through
|
||||
r();
|
||||
}
|
||||
</pre>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="targetspecific">Target-Specific Extensions</h2>
|
||||
|
|
|
|||
229
docs/LibTooling.html
Normal file
229
docs/LibTooling.html
Normal file
|
|
@ -0,0 +1,229 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
|
||||
"http://www.w3.org/TR/html4/strict.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>LibTooling</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>LibTooling</h1>
|
||||
<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>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<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. -->
|
||||
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.</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:
|
||||
<pre>
|
||||
#include "clang/Tooling/Tooling.h"
|
||||
|
||||
TEST(runToolOnCode, CanSyntaxCheckCode) {
|
||||
// runToolOnCode returns whether the action was correctly run over the
|
||||
// given code.
|
||||
EXPECT_TRUE(runToolOnCode(new clang::SyntaxOnlyAction, "class X {};"));
|
||||
}
|
||||
</pre>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<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>
|
||||
|
||||
<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.
|
||||
<pre>
|
||||
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));
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
</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:
|
||||
<pre>
|
||||
// A clang tool can run over a number of sources in the same process...
|
||||
std::vector<std::string> Sources;
|
||||
Sources.push_back("a.cc");
|
||||
Sources.push_back("b.cc");
|
||||
|
||||
// We hand the CompilationDatabase we created and the sources to run over into
|
||||
// the tool constructor.
|
||||
ClangTool Tool(*Compilations, Sources);
|
||||
|
||||
// The ClangTool needs a new FrontendAction for each translation unit we run
|
||||
// on. Thus, it takes a FrontendActionFactory as parameter. To create a
|
||||
// FrontendActionFactory from a given FrontendAction type, we call
|
||||
// newFrontendActionFactory<clang::SyntaxOnlyAction>().
|
||||
int result = Tool.run(newFrontendActionFactory<clang::SyntaxOnlyAction>());
|
||||
</pre>
|
||||
</p>
|
||||
|
||||
<h3 id="main">Putting it together - the first tool.</h3>
|
||||
<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"
|
||||
#include "clang/Frontend/FrontendActions.h"
|
||||
#include "clang/Tooling/CompilationDatabase.h"
|
||||
#include "clang/Tooling/Tooling.h"
|
||||
|
||||
using namespace clang::tooling;
|
||||
using namespace llvm;
|
||||
|
||||
cl::opt<std::string> BuildPath(
|
||||
"p",
|
||||
cl::desc("<build-path>"),
|
||||
cl::Optional);
|
||||
|
||||
cl::list<std::string> SourcePaths(
|
||||
cl::Positional,
|
||||
cl::desc("<source0> [... <sourceN>]"),
|
||||
cl::OneOrMore);
|
||||
|
||||
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>());
|
||||
}
|
||||
</pre>
|
||||
</p>
|
||||
|
||||
<h3 id="running">Running the tool on some code.</h3>
|
||||
<p>When you check out and build clang, clang-check is already built and
|
||||
available to you in bin/clang-check inside your build directory.</p>
|
||||
<p>You can run clang-check on a file in the llvm repository by specifying
|
||||
all the needed parameters after a "--" separator:
|
||||
<pre>
|
||||
$ cd /path/to/source/llvm
|
||||
$ export BD=/path/to/build/llvm
|
||||
$ $BD/bin/clang-check tools/clang/tools/clang-check/ClangCheck.cpp -- \
|
||||
clang++ -D__STDC_CONSTANT_MACROS -D__STDC_LIMIT_MACROS \
|
||||
-Itools/clang/include -I$BD/include -Iinclude -Itools/clang/lib/Headers -c
|
||||
</pre>
|
||||
</p>
|
||||
|
||||
<p>As an alternative, you can also configure cmake to output a compile command
|
||||
database into its build directory:
|
||||
<pre>
|
||||
# Alternatively to calling cmake, use ccmake, toggle to advanced mode and
|
||||
# set the parameter CMAKE_EXPORT_COMPILE_COMMANDS from the UI.
|
||||
$ cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON .
|
||||
</pre>
|
||||
</p>
|
||||
<p>
|
||||
This creates a file called compile_commands.json in the build directory. Now
|
||||
you can run clang-check over files in the project by specifying the build path
|
||||
as first argument and some source files as further positional arguments:
|
||||
<pre>
|
||||
$ cd /path/to/source/llvm
|
||||
$ export BD=/path/to/build/llvm
|
||||
$ $BD/bin/clang-check -p $BD tools/clang/tools/clang-check/ClangCheck.cpp
|
||||
</pre>
|
||||
</p>
|
||||
|
||||
<h3 id="builtin">Builtin includes.</h3>
|
||||
<p>Clang tools need their builtin headers and search for them the same way clang
|
||||
does. Thus, the default location to look for builtin headers is in a path
|
||||
$(dirname /path/to/tool)/../lib/clang/3.2/include relative to the tool
|
||||
binary. This works out-of-the-box for tools running from llvm's toplevel
|
||||
binary directory after building clang-headers, or if the tool is running
|
||||
from the binary directory of a clang install next to the clang binary.</p>
|
||||
|
||||
<p>Tips: if your tool fails to find stddef.h or similar headers, call
|
||||
the tool with -v and look at the search paths it looks through.</p>
|
||||
|
||||
<h3 id="linking">Linking.</h3>
|
||||
<p>Please note that this presents the linking requirements at the time of this
|
||||
writing. For the most up-to-date information, look at one of the tools'
|
||||
Makefiles (for example
|
||||
<a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/clang-check/Makefile?view=markup">clang-check/Makefile</a>).
|
||||
</p>
|
||||
|
||||
<p>To link a binary using the tooling infrastructure, link in the following
|
||||
libraries:
|
||||
<ul>
|
||||
<li>Tooling</li>
|
||||
<li>Frontend</li>
|
||||
<li>Driver</li>
|
||||
<li>Serialization</li>
|
||||
<li>Parse</li>
|
||||
<li>Sema</li>
|
||||
<li>Analysis</li>
|
||||
<li>Edit</li>
|
||||
<li>AST</li>
|
||||
<li>Lex</li>
|
||||
<li>Basic</li>
|
||||
</ul>
|
||||
</p>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
<html>
|
||||
<head>
|
||||
<META http-equiv="Content-Type" content="text/html; charset=UTF8">
|
||||
<title>Clang Language Extensions</title>
|
||||
<title>Objective-C Literals</title>
|
||||
<link type="text/css" rel="stylesheet" href="../menu.css">
|
||||
<link type="text/css" rel="stylesheet" href="../content.css">
|
||||
<style type="text/css">
|
||||
|
|
@ -24,21 +24,21 @@
|
|||
|
||||
<h2>Introduction</h2>
|
||||
|
||||
Three new features were introduced into clang at the same time: <i>NSNumber Literals</i> provide a syntax for creating <code>NSNumber</code> from scalar literal expressions; <i>Collection Literals</i> provide a short-hand for creating arrays and dictionaries; <i>Object Subscripting</i> provides a way to use subscripting with Objective-C objects. Users of Apple compiler releases can use these features starting with the Apple LLVM Compiler 4.0. Users of open-source LLVM.org compiler releases can use these features starting with clang v3.1.<p>
|
||||
<p>Three new features were introduced into clang at the same time: <i>NSNumber Literals</i> provide a syntax for creating <code>NSNumber</code> from scalar literal expressions; <i>Collection Literals</i> provide a short-hand for creating arrays and dictionaries; <i>Object Subscripting</i> provides a way to use subscripting with Objective-C objects. Users of Apple compiler releases can use these features starting with the Apple LLVM Compiler 4.0. Users of open-source LLVM.org compiler releases can use these features starting with clang v3.1.</p>
|
||||
|
||||
These language additions simplify common Objective-C programming patterns, make programs more concise, and improve the safety of container creation.<p>
|
||||
<p>These language additions simplify common Objective-C programming patterns, make programs more concise, and improve the safety of container creation.</p>
|
||||
|
||||
This document describes how the features are implemented in clang, and how to use them in your own programs.<p>
|
||||
<p>This document describes how the features are implemented in clang, and how to use them in your own programs.</p>
|
||||
|
||||
<h2>NSNumber Literals</h2>
|
||||
|
||||
The framework class <code>NSNumber</code> is used to wrap scalar values inside objects: signed and unsigned integers (<code>char</code>, <code>short</code>, <code>int</code>, <code>long</code>, <code>long long</code>), floating point numbers (<code>float</code>, <code>double</code>), and boolean values (<code>BOOL</code>, C++ <code>bool</code>). Scalar values wrapped in objects are also known as <i>boxed</i> values.<p>
|
||||
<p>The framework class <code>NSNumber</code> is used to wrap scalar values inside objects: signed and unsigned integers (<code>char</code>, <code>short</code>, <code>int</code>, <code>long</code>, <code>long long</code>), floating point numbers (<code>float</code>, <code>double</code>), and boolean values (<code>BOOL</code>, C++ <code>bool</code>). Scalar values wrapped in objects are also known as <i>boxed</i> values.</p>
|
||||
|
||||
In Objective-C, any character, numeric or boolean literal prefixed with the <code>'@'</code> character will evaluate to a pointer to an <code>NSNumber</code> object initialized with that value. C's type suffixes may be used to control the size of numeric literals.
|
||||
<p>In Objective-C, any character, numeric or boolean literal prefixed with the <code>'@'</code> character will evaluate to a pointer to an <code>NSNumber</code> object initialized with that value. C's type suffixes may be used to control the size of numeric literals.</p>
|
||||
|
||||
<h3>Examples</h3>
|
||||
|
||||
The following program illustrates the rules for <code>NSNumber</code> literals:<p>
|
||||
<p>The following program illustrates the rules for <code>NSNumber</code> literals:</p>
|
||||
|
||||
<pre>
|
||||
void main(int argc, const char *argv[]) {
|
||||
|
|
@ -68,18 +68,19 @@ void main(int argc, const char *argv[]) {
|
|||
|
||||
<h3>Discussion</h3>
|
||||
|
||||
NSNumber literals only support literal scalar values after the '@'. Consequently, @INT_MAX works, but @INT_MIN does not, because they are defined like this:<p>
|
||||
<p>NSNumber literals only support literal scalar values after the <code>'@'</code>. Consequently, <code>@INT_MAX</code> works, but <code>@INT_MIN</code> does not, because they are defined like this:</p>
|
||||
|
||||
<pre>
|
||||
#define INT_MAX 2147483647 /* max value for an int */
|
||||
#define INT_MIN (-2147483647-1) /* min value for an int */
|
||||
</pre>
|
||||
|
||||
The definition of INT_MIN is not a simple literal, but a parenthesized expression. This is by design, but may be improved in subsequent compiler releases.<p>
|
||||
<p>The definition of <code>INT_MIN</code> is not a simple literal, but a parenthesized expression. Parenthesized
|
||||
expressions are supported using the <a href="#objc_boxed_expressions">boxed expression</a> syntax, which is described in the next section.</p>
|
||||
|
||||
Because <code>NSNumber</code> does not currently support wrapping <code>long double</code> values, the use of a <code>long double NSNumber</code> literal (e.g. <code>@123.23L</code>) will be rejected by the compiler.<p>
|
||||
<p>Because <code>NSNumber</code> does not currently support wrapping <code>long double</code> values, the use of a <code>long double NSNumber</code> literal (e.g. <code>@123.23L</code>) will be rejected by the compiler.</p>
|
||||
|
||||
Previously, the <code>BOOL</code> type was simply a typedef for <code>signed char</code>, and <code>YES</code> and <code>NO</code> were macros that expand to <code>(BOOL)1</code> and <code>(BOOL)0</code> respectively. To support <code>@YES</code> and <code>@NO</code> expressions, these macros are now defined using new language keywords in <code><objc/objc.h></code>:<p>
|
||||
<p>Previously, the <code>BOOL</code> type was simply a typedef for <code>signed char</code>, and <code>YES</code> and <code>NO</code> were macros that expand to <code>(BOOL)1</code> and <code>(BOOL)0</code> respectively. To support <code>@YES</code> and <code>@NO</code> expressions, these macros are now defined using new language keywords in <code><objc/objc.h></code>:</p>
|
||||
|
||||
<pre>
|
||||
#if __has_feature(objc_bool)
|
||||
|
|
@ -91,26 +92,126 @@ Previously, the <code>BOOL</code> type was simply a typedef for <code>signed cha
|
|||
#endif
|
||||
</pre>
|
||||
|
||||
The compiler implicitly converts <code>__objc_yes</code> and <code>__objc_no</code> to <code>(BOOL)1</code> and <code>(BOOL)0</code>. The keywords are used to disambiguate <code>BOOL</code> and integer literals.<p>
|
||||
<p>The compiler implicitly converts <code>__objc_yes</code> and <code>__objc_no</code> to <code>(BOOL)1</code> and <code>(BOOL)0</code>. The keywords are used to disambiguate <code>BOOL</code> and integer literals.</p>
|
||||
|
||||
Objective-C++ also supports <code>@true</code> and <code>@false</code> expressions, which are equivalent to <code>@YES</code> and <code>@NO</code>.
|
||||
<p>Objective-C++ also supports <code>@true</code> and <code>@false</code> expressions, which are equivalent to <code>@YES</code> and <code>@NO</code>.</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="objc_boxed_expressions">Boxed Expressions</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>Objective-C provides a new syntax for boxing C expressions:</p>
|
||||
|
||||
<pre>
|
||||
<code>@( <em>expression</em> )</code>
|
||||
</pre>
|
||||
|
||||
<p>Expressions of scalar (numeric, enumerated, BOOL) and C string pointer types
|
||||
are supported:</p>
|
||||
|
||||
<pre>
|
||||
// numbers.
|
||||
NSNumber *smallestInt = @(-INT_MAX - 1); // [NSNumber numberWithInt:(-INT_MAX - 1)]
|
||||
NSNumber *piOverTwo = @(M_PI / 2); // [NSNumber numberWithDouble:(M_PI / 2)]
|
||||
|
||||
// enumerated types.
|
||||
typedef enum { Red, Green, Blue } Color;
|
||||
NSNumber *favoriteColor = @(Green); // [NSNumber numberWithInt:((int)Green)]
|
||||
|
||||
// strings.
|
||||
NSString *path = @(getenv("PATH")); // [NSString stringWithUTF8String:(getenv("PATH"))]
|
||||
NSArray *pathComponents = [path componentsSeparatedByString:@":"];
|
||||
</pre>
|
||||
|
||||
<h3>Boxed Enums</h3>
|
||||
|
||||
<p>
|
||||
Cocoa frameworks frequently define constant values using <em>enums.</em> Although enum values are integral, they may not be used directly as boxed literals (this avoids conflicts with future <code>'@'</code>-prefixed Objective-C keywords). Instead, an enum value must be placed inside a boxed expression. The following example demonstrates configuring an <code>AVAudioRecorder</code> using a dictionary that contains a boxed enumeration value:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
enum {
|
||||
AVAudioQualityMin = 0,
|
||||
AVAudioQualityLow = 0x20,
|
||||
AVAudioQualityMedium = 0x40,
|
||||
AVAudioQualityHigh = 0x60,
|
||||
AVAudioQualityMax = 0x7F
|
||||
};
|
||||
|
||||
- (AVAudioRecorder *)recordToFile:(NSURL *)fileURL {
|
||||
NSDictionary *settings = @{ AVEncoderAudioQualityKey : @(AVAudioQualityMax) };
|
||||
return [[AVAudioRecorder alloc] initWithURL:fileURL settings:settings error:NULL];
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The expression <code>@(AVAudioQualityMax)</code> converts <code>AVAudioQualityMax</code> to an integer type, and boxes the value accordingly. If the enum has a <a href="http://clang.llvm.org/docs/LanguageExtensions.html#objc_fixed_enum">fixed underlying type</a> as in:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
typedef enum : unsigned char { Red, Green, Blue } Color;
|
||||
NSNumber *red = @(Red), *green = @(Green), *blue = @(Blue); // => [NSNumber numberWithUnsignedChar:]
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
then the fixed underlying type will be used to select the correct <code>NSNumber</code> creation method.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Boxing a value of enum type will result in a <code>NSNumber</code> pointer with a creation method according to the underlying type of the enum,
|
||||
which can be a <a href="http://clang.llvm.org/docs/LanguageExtensions.html#objc_fixed_enum">fixed underlying type</a> or a compiler-defined
|
||||
integer type capable of representing the values of all the members of the enumeration:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
typedef enum : unsigned char { Red, Green, Blue } Color;
|
||||
Color col = Red;
|
||||
NSNumber *nsCol = @(col); // => [NSNumber numberWithUnsignedChar:]
|
||||
</pre>
|
||||
|
||||
<h3>Boxed C Strings</h3>
|
||||
|
||||
<p>
|
||||
A C string literal prefixed by the <code>'@'</code> token denotes an <code>NSString</code> literal in the same way a numeric literal prefixed by the <code>'@'</code> token denotes an <code>NSNumber</code> literal. When the type of the parenthesized expression is <code>(char *)</code> or <code>(const char *)</code>, the result of the boxed expression is a pointer to an <code>NSString</code> object containing equivalent character data, which is assumed to be '\0'-terminated and UTF-8 encoded. The following example converts C-style command line arguments into <code>NSString</code> objects.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
// Partition command line arguments into positional and option arguments.
|
||||
NSMutableArray *args = [NSMutableArray new];
|
||||
NSMutableDictionary *options = [NSMutableArray new];
|
||||
while (--argc) {
|
||||
const char *arg = *++argv;
|
||||
if (strncmp(arg, "--", 2) == 0) {
|
||||
options[@(arg + 2)] = @(*++argv); // --key value
|
||||
} else {
|
||||
[args addObject:@(arg)]; // positional argument
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
As with all C pointers, character pointer expressions can involve arbitrary pointer arithmetic, therefore programmers must ensure that the character data is valid. Passing <code>NULL</code> as the character pointer will raise an exception at runtime. When possible, the compiler will reject <code>NULL</code> character pointers used in boxed expressions.
|
||||
</p>
|
||||
|
||||
<h3>Availability</h3>
|
||||
|
||||
<p>Boxed expressions will be available in clang 3.2. It is not currently available in any Apple compiler.</p>
|
||||
|
||||
<h2>Container Literals</h2>
|
||||
|
||||
Objective-C now supports a new expression syntax for creating immutable array and dictionary container objects.
|
||||
<p>Objective-C now supports a new expression syntax for creating immutable array and dictionary container objects.</p>
|
||||
|
||||
<h3>Examples</h3>
|
||||
|
||||
Immutable array expression:<p>
|
||||
<p>Immutable array expression:</p>
|
||||
|
||||
<pre>
|
||||
<pre>
|
||||
NSArray *array = @[ @"Hello", NSApp, [NSNumber numberWithInt:42] ];
|
||||
</pre>
|
||||
|
||||
This creates an <code>NSArray</code> with 3 elements. The comma-separated sub-expressions of an array literal can be any Objective-C object pointer typed expression.<p>
|
||||
<p>This creates an <code>NSArray</code> with 3 elements. The comma-separated sub-expressions of an array literal can be any Objective-C object pointer typed expression.</p>
|
||||
|
||||
Immutable dictionary expression:<p>
|
||||
<p>Immutable dictionary expression:</p>
|
||||
|
||||
<pre>
|
||||
NSDictionary *dictionary = @{
|
||||
|
|
@ -120,21 +221,21 @@ NSDictionary *dictionary = @{
|
|||
};
|
||||
</pre>
|
||||
|
||||
This creates an <code>NSDictionary</code> with 3 key/value pairs. Value sub-expressions of a dictionary literal must be Objective-C object pointer typed, as in array literals. Key sub-expressions must be of an Objective-C object pointer type that implements the <code><NSCopying></code> protocol.<p>
|
||||
<p>This creates an <code>NSDictionary</code> with 3 key/value pairs. Value sub-expressions of a dictionary literal must be Objective-C object pointer typed, as in array literals. Key sub-expressions must be of an Objective-C object pointer type that implements the <code><NSCopying></code> protocol.</p>
|
||||
|
||||
<h3>Discussion</h3>
|
||||
|
||||
Neither keys nor values can have the value <code>nil</code> in containers. If the compiler can prove that a key or value is <code>nil</code> at compile time, then a warning will be emitted. Otherwise, a runtime error will occur.<p>
|
||||
<p>Neither keys nor values can have the value <code>nil</code> in containers. If the compiler can prove that a key or value is <code>nil</code> at compile time, then a warning will be emitted. Otherwise, a runtime error will occur.</p>
|
||||
|
||||
Using array and dictionary literals is safer than the variadic creation forms commonly in use today. Array literal expressions expand to calls to <code>+[NSArray arrayWithObjects:count:]</code>, which validates that all objects are non-<code>nil</code>. The variadic form, <code>+[NSArray arrayWithObjects:]</code> uses <code>nil</code> as an argument list terminator, which can lead to malformed array objects. Dictionary literals are similarly created with <code>+[NSDictionary dictionaryWithObjects:forKeys:count:]</code> which validates all objects and keys, unlike <code>+[NSDictionary dictionaryWithObjectsAndKeys:]</code> which also uses a <code>nil</code> parameter as an argument list terminator.<p>
|
||||
<p>Using array and dictionary literals is safer than the variadic creation forms commonly in use today. Array literal expressions expand to calls to <code>+[NSArray arrayWithObjects:count:]</code>, which validates that all objects are non-<code>nil</code>. The variadic form, <code>+[NSArray arrayWithObjects:]</code> uses <code>nil</code> as an argument list terminator, which can lead to malformed array objects. Dictionary literals are similarly created with <code>+[NSDictionary dictionaryWithObjects:forKeys:count:]</code> which validates all objects and keys, unlike <code>+[NSDictionary dictionaryWithObjectsAndKeys:]</code> which also uses a <code>nil</code> parameter as an argument list terminator.</p>
|
||||
|
||||
<h2>Object Subscripting</h2>
|
||||
|
||||
Objective-C object pointer values can now be used with C's subscripting operator.<p>
|
||||
<p>Objective-C object pointer values can now be used with C's subscripting operator.</p>
|
||||
|
||||
<h3>Examples</h3>
|
||||
|
||||
The following code demonstrates the use of object subscripting syntax with <code>NSMutableArray</code> and <code>NSMutableDictionary</code> objects:<p>
|
||||
<p>The following code demonstrates the use of object subscripting syntax with <code>NSMutableArray</code> and <code>NSMutableDictionary</code> objects:</p>
|
||||
|
||||
<pre>
|
||||
NSMutableArray *array = ...;
|
||||
|
|
@ -149,87 +250,93 @@ oldObject = dictionary[key];
|
|||
dictionary[key] = newObject; // replace oldObject with newObject
|
||||
</pre>
|
||||
|
||||
The next section explains how subscripting expressions map to accessor methods.<p>
|
||||
<p>The next section explains how subscripting expressions map to accessor methods.</p>
|
||||
|
||||
<h3>Subscripting Methods</h3>
|
||||
|
||||
Objective-C supports two kinds of subscript expressions: <i>array-style</i> subscript expressions use integer typed subscripts; <i>dictionary-style</i> subscript expressions use Objective-C object pointer typed subscripts. Each type of subscript expression is mapped to a message send using a predefined selector. The advantage of this design is flexibility: class designers are free to introduce subscripting by declaring methods or by adopting protocols. Moreover, because the method names are selected by the type of the subscript, an object can be subscripted using both array and dictionary styles.
|
||||
<p>Objective-C supports two kinds of subscript expressions: <i>array-style</i> subscript expressions use integer typed subscripts; <i>dictionary-style</i> subscript expressions use Objective-C object pointer typed subscripts. Each type of subscript expression is mapped to a message send using a predefined selector. The advantage of this design is flexibility: class designers are free to introduce subscripting by declaring methods or by adopting protocols. Moreover, because the method names are selected by the type of the subscript, an object can be subscripted using both array and dictionary styles.</p>
|
||||
|
||||
<h4>Array-Style Subscripting</h4>
|
||||
|
||||
When the subscript operand has an integral type, the expression is rewritten to use one of two different selectors, depending on whether the element is being read or written. When an expression reads an element using an integral index, as in the following example:<p>
|
||||
<p>When the subscript operand has an integral type, the expression is rewritten to use one of two different selectors, depending on whether the element is being read or written. When an expression reads an element using an integral index, as in the following example:</p>
|
||||
|
||||
<pre>
|
||||
NSUInteger idx = ...;
|
||||
id value = object[idx];
|
||||
</pre>
|
||||
|
||||
it is translated into a call to <code>objectAtIndexedSubscript:</code><p>
|
||||
<p>it is translated into a call to <code>objectAtIndexedSubscript:</code></p>
|
||||
|
||||
<pre>
|
||||
id value = [object objectAtIndexedSubscript:idx];
|
||||
</pre>
|
||||
|
||||
When an expression writes an element using an integral index:<p>
|
||||
<p>When an expression writes an element using an integral index:</p>
|
||||
|
||||
<pre>
|
||||
object[idx] = newValue;
|
||||
</pre>
|
||||
|
||||
it is translated to a call to <code>setObject:atIndexedSubscript:</code><p>
|
||||
<p>it is translated to a call to <code>setObject:atIndexedSubscript:</code></p>
|
||||
|
||||
<pre>
|
||||
[object setObject:newValue atIndexedSubscript:idx];
|
||||
</pre>
|
||||
|
||||
These message sends are then type-checked and performed just like explicit message sends. The method used for objectAtIndexedSubscript: must be declared with an argument of integral type and a return value of some Objective-C object pointer type. The method used for setObject:atIndexedSubscript: must be declared with its first argument having some Objective-C pointer type and its second argument having integral type.<p>
|
||||
<p>These message sends are then type-checked and performed just like explicit message sends. The method used for objectAtIndexedSubscript: must be declared with an argument of integral type and a return value of some Objective-C object pointer type. The method used for setObject:atIndexedSubscript: must be declared with its first argument having some Objective-C pointer type and its second argument having integral type.</p>
|
||||
|
||||
The meaning of indexes is left up to the declaring class. The compiler will coerce the index to the appropriate argument type of the method it uses for type-checking. For an instance of <code>NSArray</code>, reading an element using an index outside the range <code>[0, array.count)</code> will raise an exception. For an instance of <code>NSMutableArray</code>, assigning to an element using an index within this range will replace that element, but assigning to an element using an index outside this range will raise an exception; no syntax is provided for inserting, appending, or removing elements for mutable arrays.<p>
|
||||
<p>The meaning of indexes is left up to the declaring class. The compiler will coerce the index to the appropriate argument type of the method it uses for type-checking. For an instance of <code>NSArray</code>, reading an element using an index outside the range <code>[0, array.count)</code> will raise an exception. For an instance of <code>NSMutableArray</code>, assigning to an element using an index within this range will replace that element, but assigning to an element using an index outside this range will raise an exception; no syntax is provided for inserting, appending, or removing elements for mutable arrays.</p>
|
||||
|
||||
A class need not declare both methods in order to take advantage of this language feature. For example, the class <code>NSArray</code> declares only <code>objectAtIndexedSubscript:</code>, so that assignments to elements will fail to type-check; moreover, its subclass <code>NSMutableArray</code> declares <code>setObject:atIndexedSubscript:</code>.
|
||||
<p>A class need not declare both methods in order to take advantage of this language feature. For example, the class <code>NSArray</code> declares only <code>objectAtIndexedSubscript:</code>, so that assignments to elements will fail to type-check; moreover, its subclass <code>NSMutableArray</code> declares <code>setObject:atIndexedSubscript:</code>.</p>
|
||||
|
||||
<h4>Dictionary-Style Subscripting</h4>
|
||||
|
||||
When the subscript operand has an Objective-C object pointer type, the expression is rewritten to use one of two different selectors, depending on whether the element is being read from or written to. When an expression reads an element using an Objective-C object pointer subscript operand, as in the following example:<p>
|
||||
<p>When the subscript operand has an Objective-C object pointer type, the expression is rewritten to use one of two different selectors, depending on whether the element is being read from or written to. When an expression reads an element using an Objective-C object pointer subscript operand, as in the following example:</p>
|
||||
|
||||
<pre>
|
||||
id key = ...;
|
||||
id value = object[key];
|
||||
</pre>
|
||||
|
||||
it is translated into a call to the <code>objectForKeyedSubscript:</code> method:<p>
|
||||
<p>it is translated into a call to the <code>objectForKeyedSubscript:</code> method:</p>
|
||||
|
||||
<pre>
|
||||
id value = [object objectForKeyedSubscript:key];
|
||||
</pre>
|
||||
|
||||
When an expression writes an element using an Objective-C object pointer subscript:<p>
|
||||
<p>When an expression writes an element using an Objective-C object pointer subscript:</p>
|
||||
|
||||
<pre>
|
||||
object[key] = newValue;
|
||||
</pre>
|
||||
|
||||
it is translated to a call to <code>setObject:forKeyedSubscript:</code>
|
||||
<p>it is translated to a call to <code>setObject:forKeyedSubscript:</code></p>
|
||||
|
||||
<pre>
|
||||
[object setObject:newValue forKeyedSubscript:key];
|
||||
</pre>
|
||||
|
||||
The behavior of <code>setObject:forKeyedSubscript:</code> is class-specific; but in general it should replace an existing value if one is already associated with a key, otherwise it should add a new value for the key. No syntax is provided for removing elements from mutable dictionaries.<p>
|
||||
<p>The behavior of <code>setObject:forKeyedSubscript:</code> is class-specific; but in general it should replace an existing value if one is already associated with a key, otherwise it should add a new value for the key. No syntax is provided for removing elements from mutable dictionaries.</p>
|
||||
|
||||
<h3>Discussion</h3>
|
||||
|
||||
An Objective-C subscript expression occurs when the base operand of the C subscript operator has an Objective-C object pointer type. Since this potentially collides with pointer arithmetic on the value, these expressions are only supported under the modern Objective-C runtime, which categorically forbids such arithmetic.<p>
|
||||
<p>An Objective-C subscript expression occurs when the base operand of the C subscript operator has an Objective-C object pointer type. Since this potentially collides with pointer arithmetic on the value, these expressions are only supported under the modern Objective-C runtime, which categorically forbids such arithmetic.</p>
|
||||
|
||||
Currently, only subscripts of integral or Objective-C object pointer type are supported. In C++, a class type can be used if it has a single conversion function to an integral or Objective-C pointer type, in which case that conversion is applied and analysis continues as appropriate. Otherwise, the expression is ill-formed.<p>
|
||||
<p>Currently, only subscripts of integral or Objective-C object pointer type are supported. In C++, a class type can be used if it has a single conversion function to an integral or Objective-C pointer type, in which case that conversion is applied and analysis continues as appropriate. Otherwise, the expression is ill-formed.</p>
|
||||
|
||||
An Objective-C object subscript expression is always an l-value. If the expression appears on the left-hand side of a simple assignment operator (=), the element is written as described below. If the expression appears on the left-hand side of a compound assignment operator (e.g. +=), the program is ill-formed, because the result of reading an element is always an Objective-C object pointer and no binary operators are legal on such pointers. If the expression appears in any other position, the element is read as described below. It is an error to take the address of a subscript expression, or (in C++) to bind a reference to it.<p>
|
||||
<p>An Objective-C object subscript expression is always an l-value. If the expression appears on the left-hand side of a simple assignment operator (=), the element is written as described below. If the expression appears on the left-hand side of a compound assignment operator (e.g. +=), the program is ill-formed, because the result of reading an element is always an Objective-C object pointer and no binary operators are legal on such pointers. If the expression appears in any other position, the element is read as described below. It is an error to take the address of a subscript expression, or (in C++) to bind a reference to it.</p>
|
||||
|
||||
Programs can use object subscripting with Objective-C object pointers of type <code>id</code>. Normal dynamic message send rules apply; the compiler must see <i>some</i> declaration of the subscripting methods, and will pick the declaration seen first.<p>
|
||||
<p>Programs can use object subscripting with Objective-C object pointers of type <code>id</code>. Normal dynamic message send rules apply; the compiler must see <i>some</i> declaration of the subscripting methods, and will pick the declaration seen first.</p>
|
||||
|
||||
<h2>Caveats</h2>
|
||||
|
||||
<p>Objects created using the literal or boxed expression syntax are not guaranteed to be uniqued by the runtime, but nor are they guaranteed to be newly-allocated. As such, the result of performing direct comparisons against the location of an object literal (using <code>==</code>, <code>!=</code>, <code><</code>, <code><=</code>, <code>></code>, or <code>>=</code>) is not well-defined. This is usually a simple mistake in code that intended to call the <code>isEqual:</code> method (or the <code>compare:</code> method).</p>
|
||||
|
||||
<p>This caveat applies to compile-time string literals as well. Historically, string literals (using the <code>@"..."</code> syntax) have been uniqued across translation units during linking. This is an implementation detail of the compiler and should not be relied upon. If you are using such code, please use global string constants instead (<code>NSString * const MyConst = @"..."</code>) or use <code>isEqual:</code>.</p>
|
||||
|
||||
<h2>Grammar Additions</h2>
|
||||
|
||||
To support the new syntax described above, the Objective-C <code>@</code>-expression grammar has the following new productions:<p>
|
||||
<p>To support the new syntax described above, the Objective-C <code>@</code>-expression grammar has the following new productions:</p>
|
||||
|
||||
<pre>
|
||||
objc-at-expression : '@' (string-literal | encode-literal | selector-literal | protocol-literal | object-literal)
|
||||
|
|
@ -263,11 +370,11 @@ key-value-pair : assignment-expression ':' assignment-expression
|
|||
;
|
||||
</pre>
|
||||
|
||||
Note: <code>@true</code> and <code>@false</code> are only supported in Objective-C++.<p>
|
||||
<p>Note: <code>@true</code> and <code>@false</code> are only supported in Objective-C++.</p>
|
||||
|
||||
<h2>Availability Checks</h2>
|
||||
|
||||
Programs test for the new features by using clang's __has_feature checks. Here are examples of their use:<p>
|
||||
<p>Programs test for the new features by using clang's __has_feature checks. Here are examples of their use:</p>
|
||||
|
||||
<pre>
|
||||
#if __has_feature(objc_array_literals)
|
||||
|
|
@ -307,7 +414,9 @@ Programs test for the new features by using clang's __has_feature checks. Here a
|
|||
#endif
|
||||
</pre>
|
||||
|
||||
Code can use also <code>__has_feature(objc_bool)</code> to check for the availability of numeric literals support. This checks for the new <code>__objc_yes / __objc_no</code> keywords, which enable the use of <code>@YES / @NO</code> literals.<p>
|
||||
<p>Code can use also <code>__has_feature(objc_bool)</code> to check for the availability of numeric literals support. This checks for the new <code>__objc_yes / __objc_no</code> keywords, which enable the use of <code>@YES / @NO</code> literals.</p>
|
||||
|
||||
<p>To check whether boxed expressions are supported, use <code>__has_feature(objc_boxed_expressions)</code> feature macro.</p>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
|
|
|
|||
224
docs/RAVFrontendAction.html
Normal file
224
docs/RAVFrontendAction.html
Normal file
|
|
@ -0,0 +1,224 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
|
||||
"http://www.w3.org/TR/html4/strict.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>How to write RecursiveASTVisitor based ASTFrontendActions.</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>How to write RecursiveASTVisitor based ASTFrontendActions.</h1>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="intro">Introduction</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
In this tutorial you will learn how to create a FrontendAction that uses
|
||||
a RecursiveASTVisitor to find CXXRecordDecl AST nodes with a specified name.
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="action">Creating a FrontendAction</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>When writing a clang based tool like a Clang Plugin or a standalone tool
|
||||
based on LibTooling, the common entry point is the FrontendAction.
|
||||
FrontendAction is an interface that allows execution of user specific actions
|
||||
as part of the compilation. To run tools over the AST clang provides the
|
||||
convenience interface ASTFrontendAction, which takes care of executing the
|
||||
action. The only part left is to implement the CreateASTConsumer method that
|
||||
returns an ASTConsumer per translation unit.</p>
|
||||
<pre>
|
||||
class FindNamedClassAction : public clang::ASTFrontendAction {
|
||||
public:
|
||||
virtual clang::ASTConsumer *CreateASTConsumer(
|
||||
clang::CompilerInstance &Compiler, llvm::StringRef InFile) {
|
||||
return new FindNamedClassConsumer;
|
||||
}
|
||||
};
|
||||
</pre>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="consumer">Creating an ASTConsumer</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>ASTConsumer is an interface used to write generic actions on an AST,
|
||||
regardless of how the AST was produced. ASTConsumer provides many different
|
||||
entry points, but for our use case the only one needed is HandleTranslationUnit,
|
||||
which is called with the ASTContext for the translation unit.</p>
|
||||
<pre>
|
||||
class FindNamedClassConsumer : public clang::ASTConsumer {
|
||||
public:
|
||||
virtual void HandleTranslationUnit(clang::ASTContext &Context) {
|
||||
// Traversing the translation unit decl via a RecursiveASTVisitor
|
||||
// will visit all nodes in the AST.
|
||||
Visitor.TraverseDecl(Context.getTranslationUnitDecl());
|
||||
}
|
||||
private:
|
||||
// A RecursiveASTVisitor implementation.
|
||||
FindNamedClassVisitor Visitor;
|
||||
};
|
||||
</pre>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="rav">Using the RecursiveASTVisitor</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>Now that everything is hooked up, the next step is to implement a
|
||||
RecursiveASTVisitor to extract the relevant information from the AST.</p>
|
||||
<p>The RecursiveASTVisitor provides hooks of the form
|
||||
bool VisitNodeType(NodeType *) for most AST nodes; the exception are TypeLoc
|
||||
nodes, which are passed by-value. We only need to implement the methods for the
|
||||
relevant node types.
|
||||
</p>
|
||||
<p>Let's start by writing a RecursiveASTVisitor that visits all CXXRecordDecl's.
|
||||
<pre>
|
||||
class FindNamedClassVisitor
|
||||
: public RecursiveASTVisitor<FindNamedClassVisitor> {
|
||||
public:
|
||||
bool VisitCXXRecordDecl(CXXRecordDecl *Declaration) {
|
||||
// For debugging, dumping the AST nodes will show which nodes are already
|
||||
// being visited.
|
||||
Declaration->dump();
|
||||
|
||||
// The return value indicates whether we want the visitation to proceed.
|
||||
// Return false to stop the traversal of the AST.
|
||||
return true;
|
||||
}
|
||||
};
|
||||
</pre>
|
||||
</p>
|
||||
<p>In the methods of our RecursiveASTVisitor we can now use the full power of
|
||||
the Clang AST to drill through to the parts that are interesting for us. For
|
||||
example, to find all class declaration with a certain name, we can check for a
|
||||
specific qualified name:
|
||||
<pre>
|
||||
bool VisitCXXRecordDecl(CXXRecordDecl *Declaration) {
|
||||
if (Declaration->getQualifiedNameAsString() == "n::m::C")
|
||||
Declaration->dump();
|
||||
return true;
|
||||
}
|
||||
</pre>
|
||||
</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="context">Accessing the SourceManager and ASTContext</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>Some of the information about the AST, like source locations and global
|
||||
identifier information, are not stored in the AST nodes themselves, but in
|
||||
the ASTContext and its associated source manager. To retrieve them we need to
|
||||
hand the ASTContext into our RecursiveASTVisitor implementation.</p>
|
||||
<p>The ASTContext is available from the CompilerInstance during the call
|
||||
to CreateASTConsumer. We can thus extract it there and hand it into our
|
||||
freshly created FindNamedClassConsumer:</p>
|
||||
<pre>
|
||||
virtual clang::ASTConsumer *CreateASTConsumer(
|
||||
clang::CompilerInstance &Compiler, llvm::StringRef InFile) {
|
||||
return new FindNamedClassConsumer(<b>&Compiler.getASTContext()</b>);
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>Now that the ASTContext is available in the RecursiveASTVisitor, we can do
|
||||
more interesting things with AST nodes, like looking up their source
|
||||
locations:</p>
|
||||
<pre>
|
||||
bool VisitCXXRecordDecl(CXXRecordDecl *Declaration) {
|
||||
if (Declaration->getQualifiedNameAsString() == "n::m::C") {
|
||||
// getFullLoc uses the ASTContext's SourceManager to resolve the source
|
||||
// location and break it up into its line and column parts.
|
||||
FullSourceLoc FullLocation = Context->getFullLoc(Declaration->getLocStart());
|
||||
if (FullLocation.isValid())
|
||||
llvm::outs() << "Found declaration at "
|
||||
<< FullLocation.getSpellingLineNumber() << ":"
|
||||
<< FullLocation.getSpellingColumnNumber() << "\n";
|
||||
}
|
||||
return true;
|
||||
}
|
||||
</pre>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="full">Putting it all together</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>Now we can combine all of the above into a small example program:</p>
|
||||
<pre>
|
||||
#include "clang/AST/ASTConsumer.h"
|
||||
#include "clang/AST/RecursiveASTVisitor.h"
|
||||
#include "clang/Frontend/CompilerInstance.h"
|
||||
#include "clang/Frontend/FrontendAction.h"
|
||||
#include "clang/Tooling/Tooling.h"
|
||||
|
||||
using namespace clang;
|
||||
|
||||
class FindNamedClassVisitor
|
||||
: public RecursiveASTVisitor<FindNamedClassVisitor> {
|
||||
public:
|
||||
explicit FindNamedClassVisitor(ASTContext *Context)
|
||||
: Context(Context) {}
|
||||
|
||||
bool VisitCXXRecordDecl(CXXRecordDecl *Declaration) {
|
||||
if (Declaration->getQualifiedNameAsString() == "n::m::C") {
|
||||
FullSourceLoc FullLocation = Context->getFullLoc(Declaration->getLocStart());
|
||||
if (FullLocation.isValid())
|
||||
llvm::outs() << "Found declaration at "
|
||||
<< FullLocation.getSpellingLineNumber() << ":"
|
||||
<< FullLocation.getSpellingColumnNumber() << "\n";
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
ASTContext *Context;
|
||||
};
|
||||
|
||||
class FindNamedClassConsumer : public clang::ASTConsumer {
|
||||
public:
|
||||
explicit FindNamedClassConsumer(ASTContext *Context)
|
||||
: Visitor(Context) {}
|
||||
|
||||
virtual void HandleTranslationUnit(clang::ASTContext &Context) {
|
||||
Visitor.TraverseDecl(Context.getTranslationUnitDecl());
|
||||
}
|
||||
private:
|
||||
FindNamedClassVisitor Visitor;
|
||||
};
|
||||
|
||||
class FindNamedClassAction : public clang::ASTFrontendAction {
|
||||
public:
|
||||
virtual clang::ASTConsumer *CreateASTConsumer(
|
||||
clang::CompilerInstance &Compiler, llvm::StringRef InFile) {
|
||||
return new FindNamedClassConsumer(&Compiler.getASTContext());
|
||||
}
|
||||
};
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (argc > 1) {
|
||||
clang::tooling::runToolOnCode(new FindNamedClassAction, argv[1]);
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>We store this into a file called FindClassDecls.cpp and create the following
|
||||
CMakeLists.txt to link it:</p>
|
||||
<pre>
|
||||
set(LLVM_USED_LIBS clangTooling)
|
||||
|
||||
add_clang_executable(find-class-decls FindClassDecls.cpp)
|
||||
</pre>
|
||||
|
||||
<p>When running this tool over a small code snippet it will output all
|
||||
declarations of a class n::m::C it found:</p>
|
||||
<pre>
|
||||
$ ./bin/find-class-decls "namespace n { namespace m { class C {}; } }"
|
||||
Found declaration at 1:29
|
||||
</pre>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
"http://www.w3.org/TR/html4/strict.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Clang 3.1 Release Notes</title>
|
||||
<title>Clang 3.2 Release Notes</title>
|
||||
<link type="text/css" rel="stylesheet" href="../menu.css">
|
||||
<link type="text/css" rel="stylesheet" href="../content.css">
|
||||
<style type="text/css">
|
||||
|
|
@ -17,21 +17,25 @@ td {
|
|||
|
||||
<div id="content">
|
||||
|
||||
<h1>Clang 3.1 Release Notes</h1>
|
||||
<h1>Clang 3.2 Release Notes</h1>
|
||||
|
||||
<img style="float:right" src="http://llvm.org/img/DragonSmall.png"
|
||||
width="136" height="136" alt="LLVM Dragon Logo">
|
||||
|
||||
<ul>
|
||||
<li><a href="#intro">Introduction</a></li>
|
||||
<li><a href="#whatsnew">What's New in Clang 3.1?</a>
|
||||
<li><a href="#whatsnew">What's New in Clang 3.2?</a>
|
||||
<ul>
|
||||
<li><a href="#majorfeatures">Major New Features</a></li>
|
||||
<li><a href="#newflags">New Compiler Flags</a></li>
|
||||
<li><a href="#cchanges">C Language Changes</a></li>
|
||||
<li><a href="#cxxchanges">C++ Language Changes</a></li>
|
||||
<li><a href="#objcchanges">Objective-C Language Changes</a></li>
|
||||
<li><a href="#apichanges">Internal API Changes</a></li>
|
||||
<li><a href="#pythonchanges">Python Binding Changes</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#knownproblems">Known Problems</a></li>
|
||||
<li><a href="#additionalinfo">Additional Information</a></li>
|
||||
</ul>
|
||||
|
||||
|
|
@ -39,36 +43,166 @@ td {
|
|||
<p>Written by the <a href="http://llvm.org/">LLVM Team</a></p>
|
||||
</div>
|
||||
|
||||
<h1 style="color:red">These are in-progress notes for the upcoming Clang 3.2
|
||||
release.<br>
|
||||
You may prefer the
|
||||
<a href="http://llvm.org/releases/3.1/docs/ClangReleaseNotes.html">Clang 3.1
|
||||
Release Notes</a>.</h1>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="intro">Introduction</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>This document contains the release notes for the Clang C/C++/Objective-C
|
||||
frontend, part of the LLVM Compiler Infrastructure, release 3.1. Here we
|
||||
describe the status of Clang in some detail, including major improvements from
|
||||
the previous release and new feature work. For the general LLVM release notes,
|
||||
see <a href="http://llvm.org/docs/ReleaseNotes.html">the LLVM
|
||||
documentation</a>. All LLVM releases may be downloaded from the
|
||||
<a href="http://llvm.org/releases/">LLVM releases web site</a>.</p>
|
||||
frontend, part of the LLVM Compiler Infrastructure, release 3.2. Here we
|
||||
describe the status of Clang in some detail, including major improvements
|
||||
from the previous release and new feature work. For the general LLVM release
|
||||
notes, see <a href="http://llvm.org/docs/ReleaseNotes.html">the LLVM
|
||||
documentation</a>. All LLVM releases may be downloaded from the
|
||||
<a href="http://llvm.org/releases/">LLVM releases web site</a>.</p>
|
||||
|
||||
<p>For more information about Clang or LLVM, including information about the
|
||||
latest release, please check out the main please see the
|
||||
<a href="http://clang.llvm.org">Clang Web Site</a> or the
|
||||
<a href="http://llvm.org">LLVM Web Site</a>.
|
||||
latest release, please check out the main please see the
|
||||
<a href="http://clang.llvm.org">Clang Web Site</a> or the
|
||||
<a href="http://llvm.org">LLVM Web Site</a>.
|
||||
|
||||
<p>Note that if you are reading this file from a Subversion checkout or the main
|
||||
Clang web page, this document applies to the <i>next</i> release, not the
|
||||
current one. To see the release notes for a specific release, please see the
|
||||
<a href="http://llvm.org/releases/">releases page</a>.</p>
|
||||
Clang web page, this document applies to the <i>next</i> release, not the
|
||||
current one. To see the release notes for a specific release, please see the
|
||||
<a href="http://llvm.org/releases/">releases page</a>.</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="whatsnew">What's New in Clang 3.1?</h2>
|
||||
<h2 id="whatsnew">What's New in Clang 3.2?</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>Some of the major new features and improvements to Clang are listed here.
|
||||
Generic improvements to Clang as a whole or two its underlying infrastructure
|
||||
are described first, followed by language-specific sections with improvements to
|
||||
Clang's support for those languages.</p>
|
||||
Generic improvements to Clang as a whole or to its underlying infrastructure
|
||||
are described first, followed by language-specific sections with improvements
|
||||
to Clang's support for those languages.</p>
|
||||
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
<h3 id="majorfeatures">Major New Features</h3>
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
|
||||
<h4 id="diagnostics">Improvements to Clang's diagnostics</h4>
|
||||
|
||||
<p>Clang's diagnostics are constantly being improved to catch more issues,
|
||||
explain them more clearly, and provide more accurate source information about
|
||||
them. The improvements since the 3.1 release include:</p>
|
||||
|
||||
<ul>
|
||||
<li><tt>-Wuninitialized</tt> has been taught to recognise uninitialized uses
|
||||
which always occur when an explicitly-written non-constant condition is either
|
||||
<tt>true</tt> or <tt>false</tt>. For example:
|
||||
|
||||
<pre>
|
||||
int f(bool b) {
|
||||
int n;
|
||||
if (b)
|
||||
n = 1;
|
||||
return n;
|
||||
}
|
||||
|
||||
<b>sometimes-uninit.cpp:3:7: <span class="warning">warning:</span> variable 'n' is used uninitialized whenever 'if' condition is false [-Wsometimes-uninitialized]</b>
|
||||
if (b)
|
||||
<span class="caret">^</span>
|
||||
<b>sometimes-uninit.cpp:5:10: <span class="note">note:</span></b> uninitialized use occurs here
|
||||
return n;
|
||||
<span class="caret">^</span>
|
||||
<b>sometimes-uninit.cpp:3:3: <span class="note">note:</span></b> remove the 'if' if its condition is always true
|
||||
if (b)
|
||||
<span class="caret">^~~~~~</span>
|
||||
<b>sometimes-uninit.cpp:2:8: <span class="note">note:</span></b> initialize the variable 'n' to silence this warning
|
||||
int n;
|
||||
<span class="caret">^</span>
|
||||
<span class="caret"> = 0</span>
|
||||
</pre>
|
||||
|
||||
This functionality can be enabled or disabled separately from
|
||||
<tt>-Wuninitialized</tt> with the <tt>-Wsometimes-uninitialized</tt> warning
|
||||
flag.</li>
|
||||
|
||||
<li>Template type diffing improves the display of diagnostics with templated
|
||||
types in them.
|
||||
|
||||
<pre>
|
||||
int f(vector<map<int, double>>);
|
||||
int x = f(vector<map<int, float>>());
|
||||
</pre>
|
||||
The error message is the same, but the note is different based on the options selected.
|
||||
<pre>
|
||||
<b>template-diff.cpp:5:9: <span class="error">error:</span> no matching function for call to 'f'</b>
|
||||
int x = f(vector<map<int, float>>());
|
||||
<span class="caret">^</span>
|
||||
</pre>
|
||||
Templated type diffing with type elision (default):
|
||||
<pre>
|
||||
<b>template-diff.cpp:4:5: <span class="note">note:</span></b> candidate function not viable: no known conversion from 'vector<map<[...], <span class="template-highlight">float</span>>>' to 'vector<map<[...], <span class="template-highlight">double</span>>>' for 1st argument;
|
||||
int f(vector<map<int, double>>);
|
||||
<span class="caret">^</span>
|
||||
</pre>
|
||||
Templated type diffing without type elision (-fno-elide-type):
|
||||
<pre>
|
||||
<b>template-diff.cpp:4:5: <span class="note">note:</span></b> candidate function not viable: no known conversion from 'vector<map<int, <span class="template-highlight">float</span>>>' to 'vector<map<int, <span class="template-highlight">double</span>>>' for 1st argument;
|
||||
int f(vector<map<int, double>>);
|
||||
<span class="caret">^</span>
|
||||
</pre>
|
||||
Templated tree printing with type elision (-fdiagnostics-show-template-tree):
|
||||
<pre>
|
||||
<b>template-diff.cpp:4:5: <span class="note">note:</span></b> candidate function not viable: no known conversion for 1st argument;
|
||||
vector<
|
||||
map<
|
||||
[...],
|
||||
[<span class="template-highlight">float</span> != <span class="template-highlight">double</span>]>>
|
||||
int f(vector<map<int, double>>);
|
||||
<span class="caret">^</span>
|
||||
</pre>
|
||||
Templated tree printing without type elision (-fdiagnostics-show-template-tree -fno-elide-type):
|
||||
<pre>
|
||||
<b>template-diff.cpp:4:5: <span class="note">note:</span></b> candidate function not viable: no known conversion for 1st argument;
|
||||
vector<
|
||||
map<
|
||||
int,
|
||||
[<span class="template-highlight">float</span> != <span class="template-highlight">double</span>]>>
|
||||
int f(vector<map<int, double>>);
|
||||
<span class="caret">^</span>
|
||||
</pre>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
<h4 id="tlsmodel">Support for <code>tls_model</code> attribute</h4>
|
||||
|
||||
<p>Clang now supports the <code>tls_model</code> attribute, allowing code that
|
||||
uses thread-local storage to explicitly select which model to use. The available
|
||||
models are <code>"global-dynamic"</code>, <code>"local-dynamic"</code>,
|
||||
<code>"initial-exec"</code> and <code>"local-exec"</code>. See
|
||||
<a href="http://www.akkadia.org/drepper/tls.pdf">ELF Handling For Thread-Local
|
||||
Storage</a> for more information.</p>
|
||||
|
||||
<p>The compiler is free to choose a different model if the specified model is not
|
||||
supported by the target, or if the compiler determines that a more specific
|
||||
model can be used.
|
||||
</p>
|
||||
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
<h3 id="newflags">New Compiler Flags</h3>
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
<ul>
|
||||
<li><tt>-gline-tables-only</tt> controls the
|
||||
<a href="http://clang.llvm.org/docs/UsersManual.html#debuginfosize">size of debug information</a>.
|
||||
This flag tells Clang to emit debug info which is just enough to obtain stack traces with
|
||||
function names, file names and line numbers (by such tools as gdb or addr2line).
|
||||
Debug info for variables or function parameters is not produced, which reduces
|
||||
the size of the resulting binary.
|
||||
|
||||
<li><tt>-ftls-model</tt> controls which TLS model to use for thread-local
|
||||
variables. This can be overridden per variable using the
|
||||
<a href="#tlsmodel"><tt>tls_model</tt> attribute</a> mentioned above.
|
||||
For more details, see the <a href="UsersManual.html#opt_ftls-model">User's
|
||||
Manual</a>.</li>
|
||||
</ul>
|
||||
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
<h3 id="cchanges">C Language Changes in Clang</h3>
|
||||
|
|
@ -76,51 +210,33 @@ Clang's support for those languages.</p>
|
|||
|
||||
<h4 id="c11changes">C11 Feature Support</h4>
|
||||
|
||||
<p>Clang 3.1 adds support for anonymous structs and anonymous unions, added in
|
||||
the latest ISO C standard. Use <code>-std=c11</code> or <code>-std=gnu11</code>
|
||||
to enable support for the new language standard. The new C11 features are
|
||||
backwards-compatible and are available as an extension in all language
|
||||
modes.</p>
|
||||
|
||||
<p>All warning and language selection flags which previously accepted
|
||||
<code>c1x</code> have been updated to accept <code>c11</code>. The old
|
||||
<code>c1x</code> forms have been removed.
|
||||
<p>...</p>
|
||||
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
<h3 id="cxxchanges">C++ Language Changes in Clang</h3>
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
|
||||
<h4 id="cxx11changes">C++11 Feature Support</h4>
|
||||
<p>Clang 3.1 supports
|
||||
<a href="http://clang.llvm.org/cxx_status.html#cxx11">most of the language
|
||||
features</a> added in the latest ISO C++ standard,
|
||||
<a href="http://www.iso.org/iso/iso_catalogue/catalogue_tc/catalogue_detail.htm?csnumber=50372">C++ 2011</a>.
|
||||
Use <code>-std=c++11</code> or <code>-std=gnu++11</code> to enable support for
|
||||
these features. In addition to the features supported by Clang 3.0, the
|
||||
following are now considered to be of production quality:
|
||||
<ul>
|
||||
<li>Generalized constant expressions</li>
|
||||
<li>Lambda expressions</li>
|
||||
<li>Generalized initializers</li>
|
||||
<li>Unrestricted unions</li>
|
||||
<li>User-defined literals</li>
|
||||
<li>Forward-declared enumerations</li>
|
||||
<li>Atomics (both libc++'s and libstdc++4.7's <tt><atomic></tt> are
|
||||
supported)</li>
|
||||
</ul>
|
||||
|
||||
<p>...</p>
|
||||
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
<h3 id="objcchanges">Objective-C Language Changes in Clang</h3>
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
Clang 3.1 introduces several new Objective-C language features and improvements.
|
||||
|
||||
<h4 id="literals-subscripting">Objective-C literals and subscripting</h3>
|
||||
<p>...</p>
|
||||
|
||||
<p>Objective-C now provides additional literal expressions, including numeric, array, and dictionary literals. Additionally, array and dictionary elements can be accesses via the subscripting operator. For more information about the new literals, see the <a href="ObjectiveCLiterals.html">documentation for Objective-C literals and subscripting</a>.
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
<h3 id="apichanges">Internal API Changes</h3>
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
|
||||
<h4 id="objcwformat">Format string checking for NSString literals</h4>
|
||||
<p>These are major API changes that have happened since the 3.1 release of
|
||||
Clang. If upgrading an external codebase that uses Clang as a library, this
|
||||
section should help get you past the largest hurdles of upgrading.</p>
|
||||
|
||||
<code>-Wformat</code> now checks <code>@"NSString literals"</code>.
|
||||
<h4 id="api1">API change 1</h4>
|
||||
|
||||
<p>...</p>
|
||||
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
<h3 id="pythonchanges">Python Binding Changes</h3>
|
||||
|
|
@ -128,49 +244,40 @@ Clang 3.1 introduces several new Objective-C language features and improvements.
|
|||
|
||||
The following methods have been added:
|
||||
<ul>
|
||||
<li>SourceLocation.from_position (static)</li>
|
||||
<li>SourceLocation.__eq__ and SourceLocation.__ne__</li>
|
||||
<li>SourceRange.__eq__ and SourceRange.__ne__</li>
|
||||
<li>Diagnostic.category_number (property)</li>
|
||||
<li>Diagnostic.category_name (property)</li>
|
||||
<li>Diagnostic.option (property)</li>
|
||||
<li>Diagnostic.disable_option (property)</li>
|
||||
<li>CursorKind.is_translation_unit</li>
|
||||
<li>CursorKind.is_preprocessing</li>
|
||||
<li>CursorKind.is_unexposed</li>
|
||||
<li>Cursor.from_location (static)</li>
|
||||
<li>Cursor.underlying_typedef_type (property)</li>
|
||||
<li>Cursor.enum_type (property)</li>
|
||||
<li>Cursor.objc_type_encoding (property)</li>
|
||||
<li>Cursor.hash</li>
|
||||
<li>TypeKind.spelling</li>
|
||||
<li>Type.argument_types</li>
|
||||
<li>Type.element_type (property)</li>
|
||||
<li>Type.element_count (property)</li>
|
||||
<li>Type.is_function_variadic</li>
|
||||
<li>Type.is_pod</li>
|
||||
<li>Type.get_array_element_type</li>
|
||||
<li>Type.get_array_size</li>
|
||||
<li>Type.__eq__ and Type.__ne__</li>
|
||||
<li>File.from_name (static)</li>
|
||||
<li>File.__str__ and File.__repr__</li>
|
||||
<li>...</li>
|
||||
</ul>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="knownproblems">Significant Known Problems</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="additionalinfo">Additional Information</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>A wide variety of additional information is available on the
|
||||
<a href="http://clang.llvm.org/">Clang web page</a>. The web page contains
|
||||
versions of the API documentation which are up-to-date with the Subversion
|
||||
version of the source code. You can access versions of these documents specific
|
||||
to this release by going into the "<tt>clang/doc/</tt>" directory in the Clang
|
||||
tree.</p>
|
||||
<a href="http://clang.llvm.org/">Clang web page</a>. The web page contains
|
||||
versions of the API documentation which are up-to-date with the Subversion
|
||||
version of the source code. You can access versions of these documents
|
||||
specific to this release by going into the "<tt>clang/doc/</tt>" directory in
|
||||
the Clang tree.</p>
|
||||
|
||||
<p>If you have any questions or comments about Clang, please feel free to
|
||||
contact us via the <a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev">
|
||||
mailing list</a>.</p>
|
||||
contact us via
|
||||
the <a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev"> mailing
|
||||
list</a>.</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<!-- Likely 3.1 release notes -->
|
||||
<!-- ======================================================================= -->
|
||||
<!--
|
||||
This is just a section to hold things that have already gotten started and
|
||||
should likely pick up proper release notes in 3.1.
|
||||
|
||||
- C1X and C++11 atomics infrastructure and support
|
||||
- CUDA support?
|
||||
|
||||
-->
|
||||
|
||||
</div>
|
||||
</body>
|
||||
|
|
|
|||
125
docs/ThreadSanitizer.html
Normal file
125
docs/ThreadSanitizer.html
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
|
||||
"http://www.w3.org/TR/html4/strict.dtd">
|
||||
<!-- Material used from: HTML 4.01 specs: http://www.w3.org/TR/html401/ -->
|
||||
<html>
|
||||
<head>
|
||||
<META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>ThreadSanitizer, a race detector</title>
|
||||
<link type="text/css" rel="stylesheet" href="../menu.css">
|
||||
<link type="text/css" rel="stylesheet" href="../content.css">
|
||||
<style type="text/css">
|
||||
td {
|
||||
vertical-align: top;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!--#include virtual="../menu.html.incl"-->
|
||||
|
||||
<div id="content">
|
||||
|
||||
<h1>ThreadSanitizer</h1>
|
||||
<ul>
|
||||
<li> <a href="#intro">Introduction</a>
|
||||
<li> <a href="#howtobuild">How to Build</a>
|
||||
<li> <a href="#platforms">Supported Platforms</a>
|
||||
<li> <a href="#usage">Usage</a>
|
||||
<li> <a href="#limitations">Limitations</a>
|
||||
<li> <a href="#status">Current Status</a>
|
||||
<li> <a href="#moreinfo">More Information</a>
|
||||
</ul>
|
||||
|
||||
<h2 id="intro">Introduction</h2>
|
||||
ThreadSanitizer is a tool that detects data races. <BR>
|
||||
It consists of a compiler instrumentation module and a run-time library. <BR>
|
||||
Typical slowdown introduced by ThreadSanitizer is <b>5x-15x</b> (TODO: these numbers are
|
||||
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>.
|
||||
|
||||
<h2 id="platforms">Supported Platforms</h2>
|
||||
ThreadSanitizer is supported on Linux x86_64 (tested on Ubuntu 10.04). <BR>
|
||||
Support for MacOS 10.7 (64-bit only) is planned for late 2012. <BR>
|
||||
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>
|
||||
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>
|
||||
|
||||
Example:
|
||||
<pre>
|
||||
% cat projects/compiler-rt/lib/tsan/output_tests/tiny_race.c
|
||||
#include <pthread.h>
|
||||
int Global;
|
||||
void *Thread1(void *x) {
|
||||
Global = 42;
|
||||
return x;
|
||||
}
|
||||
int main() {
|
||||
pthread_t t;
|
||||
pthread_create(&t, NULL, Thread1, NULL);
|
||||
Global = 43;
|
||||
pthread_join(t, NULL);
|
||||
return Global;
|
||||
}
|
||||
</pre>
|
||||
|
||||
<pre>
|
||||
% clang -fthread-sanitizer -g -O1 tiny_race.c -fPIE -pie
|
||||
</pre>
|
||||
|
||||
If a bug is detected, the program will print an error message to stderr.
|
||||
Currently, ThreadSanitizer symbolizes its output using an external
|
||||
<tt>addr2line</tt>
|
||||
process (this will be fixed in future).
|
||||
<pre>
|
||||
% TSAN_OPTIONS=strip_path_prefix=`pwd`/ # Don't print full paths.
|
||||
% ./a.out 2> log
|
||||
% cat log
|
||||
WARNING: ThreadSanitizer: data race (pid=19219)
|
||||
Write of size 4 at 0x7fcf47b21bc0 by thread 1:
|
||||
#0 Thread1 tiny_race.c:4 (exe+0x00000000a360)
|
||||
Previous write of size 4 at 0x7fcf47b21bc0 by main thread:
|
||||
#0 main tiny_race.c:10 (exe+0x00000000a3b4)
|
||||
Thread 1 (running) created at:
|
||||
#0 pthread_create ??:0 (exe+0x00000000c790)
|
||||
#1 main tiny_race.c:9 (exe+0x00000000a3a4)
|
||||
</pre>
|
||||
|
||||
|
||||
<h2 id="limitations">Limitations</h2>
|
||||
<ul>
|
||||
<li> ThreadSanitizer uses more real memory than a native run.
|
||||
At the default settings the memory overhead is 9x plus 9Mb per each thread.
|
||||
Settings with 5x and 3x overhead (but less accurate analysis) are also available.
|
||||
<li> ThreadSanitizer maps (but does not reserve) a lot of virtual address space.
|
||||
This means that tools like <tt>ulimit</tt> may not work as usually expected.
|
||||
<li> Static linking is not supported.
|
||||
<li> ThreadSanitizer requires <tt>-fPIE -pie</tt>
|
||||
</ul>
|
||||
|
||||
|
||||
<h2 id="status">Current Status</h2>
|
||||
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.
|
||||
|
||||
We are actively working on enhancing the tool -- stay tuned.
|
||||
Any help, especially in the form of minimized standalone tests is more than welcome.
|
||||
|
||||
<h2 id="moreinfo">More Information</h2>
|
||||
<a href="http://code.google.com/p/thread-sanitizer/">http://code.google.com/p/thread-sanitizer</a>.
|
||||
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
120
docs/Tooling.html
Normal file
120
docs/Tooling.html
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
|
||||
"http://www.w3.org/TR/html4/strict.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Writing Clang Tools</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>Writing Clang Tools</h1>
|
||||
<p>Clang provides infrastructure to write tools that need syntactic and semantic
|
||||
information about a program. This document will give a short introduction of the
|
||||
different ways to write clang tools, and their pros and cons.</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="libclang"><a href="http://clang.llvm.org/doxygen/group__CINDEX.html">LibClang</a></h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>LibClang is a stable high level C interface to clang. When in doubt LibClang
|
||||
is probably the interface you want to use. Consider the other interfaces only
|
||||
when you have a good reason not to use LibClang.</p>
|
||||
<p>Canonical examples of when to use LibClang:</p>
|
||||
<ul>
|
||||
<li>Xcode</li>
|
||||
<li>Clang Python Bindings</li>
|
||||
</ul>
|
||||
<p>Use LibClang when you...</p>
|
||||
<ul>
|
||||
<li>want to interface with clang from other languages than C++</li>
|
||||
<li>need a stable interface that takes care to be backwards compatible</li>
|
||||
<li>want powerful high-level abstractions, like iterating through an AST
|
||||
with a cursor, and don't want to learn all the nitty gritty details of Clang's
|
||||
AST.</li>
|
||||
</ul>
|
||||
<p>Do not use LibClang when you...</p>
|
||||
<ul>
|
||||
<li>want full control over the Clang AST</li>
|
||||
</ul>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="clang-plugins"><a href="ClangPlugins.html">Clang Plugins</a></h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>Clang Plugins allow you to run additional actions on the AST as part of
|
||||
a compilation. Plugins are dynamic libraries that are loaded at runtime by
|
||||
the compiler, and they're easy to integrate into your build environment.</p>
|
||||
<p>Canonical examples of when to use Clang Plugins:</p>
|
||||
<ul>
|
||||
<li>special lint-style warnings or errors for your project</li>
|
||||
<li>creating additional build artifacts from a single compile step</li>
|
||||
</ul>
|
||||
<p>Use Clang Plugins when you...</p>
|
||||
<ul>
|
||||
<li>need your tool to rerun if any of the dependencies change</li>
|
||||
<li>want your tool to make or break a build</li>
|
||||
<li>need full control over the Clang AST</li>
|
||||
</ul>
|
||||
<p>Do not use Clang Plugins when you...</p>
|
||||
<ul>
|
||||
<li>want to run tools outside of your build environment</li>
|
||||
<li>want full control on how Clang is set up, including mapping of in-memory
|
||||
virtual files</li>
|
||||
<li>need to run over a specific subset of files in your project which is not
|
||||
necessarily related to any changes which would trigger rebuilds</li>
|
||||
</ul>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="libtooling"><a href="LibTooling.html">LibTooling</a></h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>LibTooling is a C++ interface aimed at writing standalone tools, as well as
|
||||
integrating into services that run clang tools.</p>
|
||||
<p>Canonical examples of when to use LibTooling:</p>
|
||||
<ul>
|
||||
<li>a simple syntax checker</li>
|
||||
<li>refactoring tools</li>
|
||||
</ul>
|
||||
<p>Use LibTooling when you...</p>
|
||||
<ul>
|
||||
<li>want to run tools over a single file, or a specific subset of files,
|
||||
independently of the build system</li>
|
||||
<li>want full control over the Clang AST</li>
|
||||
<li>want to share code with Clang Plugins</li>
|
||||
</ul>
|
||||
<p>Do not use LibTooling when you...</p>
|
||||
<ul>
|
||||
<li>want to run as part of the build triggered by dependency changes</li>
|
||||
<li>want a stable interface so you don't need to change your code when the
|
||||
AST API changes</li>
|
||||
<li>want high level abstractions like cursors and code completion out of the
|
||||
box</li>
|
||||
<li>do not want to write your tools in C++</li>
|
||||
</ul>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="clang-tools"><a href="ClangTools.html">Clang Tools</a></h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>These are a collection of specific developer tools built on top of the
|
||||
LibTooling infrastructure as part of the Clang project. They are targeted at
|
||||
automating and improving core development activities of C/C++ developers.</p>
|
||||
<p>Examples of tools we are building or planning as part of the Clang
|
||||
project:</p>
|
||||
<ul>
|
||||
<li>Syntax checking (clang-check)</li>
|
||||
<li>Automatic fixing of compile errors (clangc-fixit)</li>
|
||||
<li>Automatic code formatting</li>
|
||||
<li>Migration tools for new features in new language standards</li>
|
||||
<li>Core refactoring tools</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
|
@ -43,12 +43,14 @@ td {
|
|||
<li><a href="#diagnostics_categories">Diagnostic Categories</a></li>
|
||||
<li><a href="#diagnostics_commandline">Controlling Diagnostics via Command Line Flags</a></li>
|
||||
<li><a href="#diagnostics_pragmas">Controlling Diagnostics via Pragmas</a></li>
|
||||
<li><a href="#diagnostics_systemheader">Controlling Diagnostics in System Headers</a></li>
|
||||
<li><a href="#diagnostics_enable_everything">Enabling All Warnings</a></li>
|
||||
<li><a href="#analyzer_diagnositics">Controlling Static Analyzer Diagnostics</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#precompiledheaders">Precompiled Headers</a></li>
|
||||
<li><a href="#codegen">Controlling Code Generation</a></li>
|
||||
<li><a href="#debuginfosize">Controlling Size of Debug Information</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#c">C Language Features</a>
|
||||
|
|
@ -185,9 +187,10 @@ introduces the language selection and other high level options like -c, -g, etc.
|
|||
<p><b>-Werror=foo</b>: Turn warning "foo" into an error.</p>
|
||||
<p><b>-Wno-error=foo</b>: Turn warning "foo" into an warning even if -Werror is
|
||||
specified.</p>
|
||||
<p><b>-Wfoo</b>: Enable warning foo</p>
|
||||
<p><b>-Wno-foo</b>: Disable warning foo</p>
|
||||
<p><b>-Wfoo</b>: Enable warning "foo".</p>
|
||||
<p><b>-Wno-foo</b>: Disable warning "foo".</p>
|
||||
<p><b>-w</b>: Disable all warnings.</p>
|
||||
<p><b>-Weverything</b>: <a href="#diagnostics_enable_everything">Enable <b>all</b> warnings.</a></p>
|
||||
<p><b>-pedantic</b>: Warn on language extensions.</p>
|
||||
<p><b>-pedantic-errors</b>: Error on language extensions.</p>
|
||||
<p><b>-Wsystem-headers</b>: Enable warnings from system headers.</p>
|
||||
|
|
@ -227,6 +230,9 @@ print something like:
|
|||
|
||||
<p>When this is disabled, Clang will print "test.c:28: warning..." with no
|
||||
column number.</p>
|
||||
|
||||
<p>The printed column numbers count bytes from the beginning of the line; take
|
||||
care if your source contains multibyte characters.</p>
|
||||
</dd>
|
||||
|
||||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
||||
|
|
@ -393,6 +399,9 @@ exprs.c:47:15:{47:8-47:14}{47:17-47:24}: error: invalid operands to binary expre
|
|||
</pre>
|
||||
|
||||
<p>The {}'s are generated by -fdiagnostics-print-source-range-info.</p>
|
||||
|
||||
<p>The printed column numbers count bytes from the beginning of the line; take
|
||||
care if your source contains multibyte characters.</p>
|
||||
</dd>
|
||||
|
||||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
||||
|
|
@ -413,6 +422,51 @@ respectively). Both the file name and the insertion string escape backslash (as
|
|||
"\\"), tabs (as "\t"), newlines (as "\n"), double
|
||||
quotes(as "\"") and non-printable characters (as octal
|
||||
"\xxx").</p>
|
||||
|
||||
<p>The printed column numbers count bytes from the beginning of the line; take
|
||||
care if your source contains multibyte characters.</p>
|
||||
</dd>
|
||||
|
||||
<dt id="opt_fno-elide-type">
|
||||
<b>-fno-elide-type</b>:
|
||||
Turns off elision in template type printing.</dt>
|
||||
<dd><p>The default for template type printing is to elide as many template
|
||||
arguments as possible, removing those which are the same in both template types,
|
||||
leaving only the differences. Adding this flag will print all the template
|
||||
arguments. If supported by the terminal, highlighting will still appear on
|
||||
differing arguments.</p>
|
||||
|
||||
Default:
|
||||
<pre>
|
||||
t.cc:4:5: <span class="note">note</span>: candidate function not viable: no known conversion from 'vector<map<[...], map<<span class="template-highlight">float</span>, [...]>>>' to 'vector<map<[...], map<<span class="template-highlight">double</span>, [...]>>>' for 1st argument;
|
||||
</pre>
|
||||
-fno-elide-type:
|
||||
<pre>
|
||||
t.cc:4:5: <span class="note">note</span>: candidate function not viable: no known conversion from 'vector<map<int, map<<span class="template-highlight">float</span>, int>>>' to 'vector<map<int, map<<span class="template-highlight">double</span>, int>>>' for 1st argument;
|
||||
</pre>
|
||||
</dd>
|
||||
|
||||
<dt id="opt_fdiagnostics-show-template-tree">
|
||||
<b>-fdiagnostics-show-template-tree</b>:
|
||||
Template type diffing prints a text tree.</dt>
|
||||
<dd><p>For diffing large templated types, this option will cause Clang to
|
||||
display the templates as an indented text tree, one argument per line, with
|
||||
differences marked inline. This is compatible with -fno-elide-type.</p>
|
||||
|
||||
Default:
|
||||
<pre>
|
||||
t.cc:4:5: <span class="note">note</span>: candidate function not viable: no known conversion from 'vector<map<[...], map<<span class="template-highlight">float</span>, [...]>>>' to 'vector<map<[...], map<<span class="template-highlight">double</span>, [...]>>>' for 1st argument;
|
||||
</pre>
|
||||
-fdiagnostics-show-template-tree
|
||||
<pre>
|
||||
t.cc:4:5: <span class="note">note</span>: candidate function not viable: no known conversion for 1st argument;
|
||||
vector<
|
||||
map<
|
||||
[...],
|
||||
map<
|
||||
[<span class="template-highlight">float</span> != <span class="template-highlight">float</span>],
|
||||
[...]>>>
|
||||
</pre>
|
||||
</dd>
|
||||
|
||||
</dl>
|
||||
|
|
@ -443,9 +497,6 @@ the end of preprocessor directives. For example:
|
|||
|
||||
<p>These extra tokens are not strictly conforming, and are usually best handled
|
||||
by commenting them out.</p>
|
||||
|
||||
<p>This option is also enabled by <a href="">-Wfoo</a>, <a href="">-Wbar</a>,
|
||||
and <a href="">-Wbaz</a>.</p>
|
||||
</dd>
|
||||
|
||||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
||||
|
|
@ -609,7 +660,7 @@ mapping of category names to category id's can be obtained by running '<tt>clang
|
|||
<h4 id="diagnostics_commandline">Controlling Diagnostics via Command Line
|
||||
Flags</h4>
|
||||
|
||||
<p>-W flags, -pedantic, etc</p>
|
||||
<p>TODO: -W flags, -pedantic, etc</p>
|
||||
|
||||
<h4 id="diagnostics_pragmas">Controlling Diagnostics via Pragmas</h4>
|
||||
|
||||
|
|
@ -653,6 +704,45 @@ GCC do not support the exact same set of warnings, so even when using GCC
|
|||
compatible #pragmas there is no guarantee that they will have identical behaviour
|
||||
on both compilers. </p>
|
||||
|
||||
<h4 id="diagnostics_systemheader">Controlling Diagnostics in System Headers</h4>
|
||||
|
||||
<p>Warnings are suppressed when they occur in system headers. By default, an
|
||||
included file is treated as a system header if it is found in an include path
|
||||
specified by <tt>-isystem</tt>, but this can be overridden in several ways.</p>
|
||||
|
||||
<p>The <tt>system_header</tt> pragma can be used to mark the current file as
|
||||
being a system header. No warnings will be produced from the location of the
|
||||
pragma onwards within the same file.</p>
|
||||
|
||||
<pre>
|
||||
char a = 'xy'; // warning
|
||||
|
||||
#pragma clang system_header
|
||||
|
||||
char b = 'ab'; // no warning
|
||||
</pre>
|
||||
|
||||
<p>The <tt>-isystem-prefix</tt> and <tt>-ino-system-prefix</tt> command-line
|
||||
arguments can be used to override whether subsets of an include path are treated
|
||||
as system headers. When the name in a <tt>#include</tt> directive is found
|
||||
within a header search path and starts with a system prefix, the header is
|
||||
treated as a system header. The last prefix on the command-line which matches
|
||||
the specified header name takes precedence. For instance:</p>
|
||||
|
||||
<pre>
|
||||
clang -Ifoo -isystem bar -isystem-prefix x/ -ino-system-prefix x/y/
|
||||
</pre>
|
||||
|
||||
<p>Here, <tt>#include "x/a.h"</tt> is treated as including a system header, even
|
||||
if the header is found in <tt>foo</tt>, and <tt>#include "x/y/b.h"</tt> is
|
||||
treated as not including a system header, even if the header is found in
|
||||
<tt>bar</tt>.
|
||||
</p>
|
||||
|
||||
<p>A <tt>#include</tt> directive which finds a file relative to the current
|
||||
directory is treated as including a system header if the including file is
|
||||
treated as a system header.</p>
|
||||
|
||||
<h4 id="diagnostics_enable_everything">Enabling All Warnings</h4>
|
||||
|
||||
<p>In addition to the traditional <tt>-W</tt> flags, one can enable <b>all</b>
|
||||
|
|
@ -667,37 +757,11 @@ on both compilers. </p>
|
|||
|
||||
<p>While not strictly part of the compiler, the diagnostics from Clang's <a
|
||||
href="http://clang-analyzer.llvm.org">static analyzer</a> can also be influenced
|
||||
by the user via changes to the source code. This can be done in two ways:
|
||||
|
||||
<ul>
|
||||
|
||||
<li id="analyzer_annotations"><b>Annotations</b>: The static analyzer recognizes various GCC-style
|
||||
attributes (e.g., <tt>__attribute__((nonnull)))</tt>) that can either suppress
|
||||
static analyzer warnings or teach the analyzer about code invariants which
|
||||
enable it to find more bugs. While many of these attributes are standard GCC
|
||||
attributes, additional ones have been added to Clang to specifically support the
|
||||
static analyzer. Detailed information on these annotations can be found in the
|
||||
<a href="http://clang-analyzer.llvm.org/annotations.html">analyzer's
|
||||
documentation</a>.</li>
|
||||
|
||||
<li><b><tt>__clang_analyzer__</tt></b>: When the static analyzer is using Clang
|
||||
to parse source files, it implicitly defines the preprocessor macro
|
||||
<tt>__clang_analyzer__</tt>. While discouraged, code can use this macro to
|
||||
selectively exclude code the analyzer examines. Here is an example:
|
||||
|
||||
<pre>
|
||||
#ifndef __clang_analyzer__
|
||||
// Code not to be analyzed
|
||||
#endif
|
||||
</pre>
|
||||
|
||||
In general, this usage is discouraged. Instead, we prefer that users file bugs
|
||||
against the analyzer when it flags false positives. There is also active
|
||||
discussion of allowing users in the future to selectively silence specific
|
||||
analyzer warnings (some of which can already be done using <a
|
||||
href="#analyzer_annotations">annotations</a>).</li>
|
||||
|
||||
</ul>
|
||||
by the user via changes to the source code. See the available
|
||||
<a href = "http://clang-analyzer.llvm.org/annotations.html" >annotations</a> and
|
||||
the analyzer's
|
||||
<a href= "http://clang-analyzer.llvm.org/faq.html#exclude_code" >FAQ page</a> for
|
||||
more information.
|
||||
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
<h3 id="precompiledheaders">Precompiled Headers</h3>
|
||||
|
|
@ -855,6 +919,39 @@ generator will always lower the builtin to a call to the specified function
|
|||
regardless of whether the target ISA has a trap instruction. This option is
|
||||
useful for environments (e.g. deeply embedded) where a trap cannot be properly
|
||||
handled, or when some custom behavior is desired.</dd>
|
||||
|
||||
<dt id="opt_ftls-model"><b>-ftls-model=[model]</b>: Select which TLS model to
|
||||
use.</dt>
|
||||
<dd>Valid values are: <tt>global-dynamic</tt>, <tt>local-dynamic</tt>,
|
||||
<tt>initial-exec</tt> and <tt>local-exec</tt>. The default value is
|
||||
<tt>global-dynamic</tt>. The compiler may use a different model if the selected
|
||||
model is not supported by the target, or if a more efficient model can be used.
|
||||
The TLS model can be overridden per variable using the <tt>tls_model</tt>
|
||||
attribute.
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
<h3 id="debuginfosize">Controlling Size of Debug Information</h3>
|
||||
<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
|
||||
|
||||
<p>Debug info kind generated by Clang can be set by one of the flags listed
|
||||
below. If multiple flags are present, the last one is used.</p>
|
||||
|
||||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
||||
<dl>
|
||||
<dt id="opt_g0"><b>-g0</b>: Don't generate any debug info (default).
|
||||
|
||||
<dt id="opt_gline-tables-only"><b>-gline-tables-only</b>:
|
||||
Generate line number tables only.
|
||||
<dd>
|
||||
This kind of debug info allows to obtain stack traces with function
|
||||
names, file names and line numbers (by such tools as
|
||||
gdb or addr2line). It doesn't contain any other data (e.g.
|
||||
description of local variables or function parameters).
|
||||
</dd>
|
||||
|
||||
<dt id="opt_g"><b>-g</b>: Generate complete debug info.
|
||||
</dl>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
|
|
@ -937,9 +1034,18 @@ interest in these features yet, so it's hard to say when they will be
|
|||
implemented.</li>
|
||||
|
||||
<li>clang does not support nested functions; this is a complex feature which
|
||||
is infrequently used, so it is unlikely to be implemented anytime soon.</li>
|
||||
is infrequently used, so it is unlikely to be implemented anytime soon. In C++11
|
||||
it can be emulated by assigning lambda functions to local variables, e.g:
|
||||
<pre>
|
||||
auto const local_function = [&](int parameter) {
|
||||
// Do something
|
||||
};
|
||||
...
|
||||
local_function(1);
|
||||
</pre>
|
||||
</li>
|
||||
|
||||
<li>clang does not support global register variables, this is unlikely
|
||||
<li>clang does not support global register variables; this is unlikely
|
||||
to be implemented soon because it requires additional LLVM backend support.
|
||||
</li>
|
||||
|
||||
|
|
@ -955,7 +1061,7 @@ in 4.3, the glibc headers will not try to use this extension with clang at
|
|||
the moment.</li>
|
||||
|
||||
<li>clang does not support the gcc extension for forward-declaring function
|
||||
parameters; this has not showed up in any real-world code yet, though, so it
|
||||
parameters; this has not shown up in any real-world code yet, though, so it
|
||||
might never be implemented.</li>
|
||||
|
||||
</ul>
|
||||
|
|
@ -1001,6 +1107,14 @@ support is incomplete; enabling Microsoft extensions will silently drop
|
|||
certain constructs (including __declspec and Microsoft-style asm statements).
|
||||
</p>
|
||||
|
||||
<p>clang has a -fms-compatibility flag that makes clang accept enough
|
||||
invalid C++ to be able to parse most Microsoft headers. This flag is enabled by
|
||||
default for Windows targets.</p>
|
||||
|
||||
<p>-fdelayed-template-parsing lets clang delay all template instantiation until
|
||||
the end of a translation unit. This flag is enabled by default for Windows
|
||||
targets.</p>
|
||||
|
||||
<ul>
|
||||
<li>clang allows setting _MSC_VER with -fmsc-version=. It defaults to 1300 which
|
||||
is the same as Visual C/C++ 2003. Any number is supported and can greatly affect
|
||||
|
|
@ -1015,6 +1129,8 @@ record members can be declared using user defined typedefs.</li>
|
|||
controlling record layout. GCC also contains support for this feature,
|
||||
however where MSVC and GCC are incompatible clang follows the MSVC
|
||||
definition.</li>
|
||||
|
||||
<li>clang defaults to C++11 for Windows targets.</li>
|
||||
</ul>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
|
|
@ -1092,7 +1208,7 @@ Generating assembly requires a suitable LLVM backend.
|
|||
<h4 id="target_os_darwin">Darwin (Mac OS/X)</h4>
|
||||
<!-- ======================================= -->
|
||||
|
||||
<p>No __thread support, 64-bit ObjC support requires SL tools.</p>
|
||||
<p>None</p>
|
||||
|
||||
<!-- ======================================= -->
|
||||
<h4 id="target_os_win32">Windows</h4>
|
||||
|
|
@ -1100,6 +1216,8 @@ Generating assembly requires a suitable LLVM backend.
|
|||
|
||||
<p>Experimental supports are on Cygming.</p>
|
||||
|
||||
<p>See also <a href="#c_ms">Microsoft Extensions</a>.</p>
|
||||
|
||||
<h5>Cygwin</h5>
|
||||
|
||||
<p>Clang works on Cygwin-1.7.</p>
|
||||
|
|
@ -1135,7 +1253,7 @@ Clang assumes directories as below;</p>
|
|||
<li><tt>some_directory/bin/../include</tt></li>
|
||||
</ul>
|
||||
|
||||
<p>This directory layout is standard for any toolchain you will find on the official <a href="mingw-w64.sourceforge.net">MinGW-w64 website</a>.
|
||||
<p>This directory layout is standard for any toolchain you will find on the official <a href="http://mingw-w64.sourceforge.net">MinGW-w64 website</a>.
|
||||
|
||||
<p>Clang expects the GCC executable "gcc.exe" compiled for i686-w64-mingw32 (or x86_64-w64-mingw32) to be present on PATH.</p>
|
||||
|
||||
|
|
|
|||
|
|
@ -303,6 +303,14 @@ This flag sets the default visibility level.
|
|||
This flag specifies that variables without initializers get common linkage. It
|
||||
can be disabled with B<-fno-common>.
|
||||
|
||||
=item B<-ftls-model>
|
||||
|
||||
Set the default thread-local storage (TLS) model to use for thread-local
|
||||
variables. Valid values are: "global-dynamic", "local-dynamic", "initial-exec"
|
||||
and "local-exec". The default is "global-dynamic". The default model can be
|
||||
overridden with the tls_model attribute. The compiler will try to choose a more
|
||||
efficient model if possible.
|
||||
|
||||
=item B<-flto> B<-emit-llvm>
|
||||
|
||||
Generate output files in LLVM formats, suitable for link time optimization. When
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
if(NOT CLANG_BUILD_EXAMPLES)
|
||||
set(EXCLUDE_FROM_ALL ON)
|
||||
set_property(DIRECTORY PROPERTY EXCLUDE_FROM_ALL ON)
|
||||
endif()
|
||||
|
||||
add_subdirectory(analyzer-plugin)
|
||||
|
|
|
|||
|
|
@ -1,14 +1,23 @@
|
|||
set(MODULE TRUE)
|
||||
|
||||
set( LLVM_USED_LIBS
|
||||
clangFrontend
|
||||
clangAST
|
||||
)
|
||||
|
||||
set( LLVM_LINK_COMPONENTS support mc)
|
||||
|
||||
add_clang_library(PrintFunctionNames PrintFunctionNames.cpp)
|
||||
|
||||
add_dependencies(PrintFunctionNames
|
||||
ClangAttrClasses
|
||||
ClangAttrList
|
||||
ClangCommentNodes
|
||||
ClangDeclNodes
|
||||
ClangDiagnosticCommon
|
||||
ClangStmtNodes
|
||||
)
|
||||
|
||||
target_link_libraries(PrintFunctionNames
|
||||
clangFrontend
|
||||
clangAST
|
||||
)
|
||||
|
||||
set_target_properties(PrintFunctionNames
|
||||
PROPERTIES
|
||||
LINKER_LANGUAGE CXX
|
||||
|
|
|
|||
|
|
@ -1,13 +1,22 @@
|
|||
set(MODULE TRUE)
|
||||
|
||||
set( LLVM_USED_LIBS
|
||||
clangStaticAnalyzerCore
|
||||
)
|
||||
|
||||
set( LLVM_LINK_COMPONENTS support mc)
|
||||
|
||||
add_clang_library(SampleAnalyzerPlugin MainCallChecker.cpp)
|
||||
|
||||
add_dependencies(SampleAnalyzerPlugin
|
||||
ClangAttrClasses
|
||||
ClangAttrList
|
||||
ClangCommentNodes
|
||||
ClangDeclNodes
|
||||
ClangDiagnosticCommon
|
||||
ClangStmtNodes
|
||||
)
|
||||
|
||||
target_link_libraries(SampleAnalyzerPlugin
|
||||
clangStaticAnalyzerCore
|
||||
)
|
||||
|
||||
set_target_properties(SampleAnalyzerPlugin
|
||||
PROPERTIES
|
||||
LINKER_LANGUAGE CXX
|
||||
|
|
|
|||
|
|
@ -1,34 +1,37 @@
|
|||
set(LLVM_USED_LIBS
|
||||
clangFrontend
|
||||
clangSerialization
|
||||
clangDriver
|
||||
clangCodeGen
|
||||
clangSema
|
||||
clangStaticAnalyzerFrontend
|
||||
clangStaticAnalyzerCheckers
|
||||
clangStaticAnalyzerCore
|
||||
clangAnalysis
|
||||
clangRewrite
|
||||
clangAST
|
||||
clangParse
|
||||
clangLex
|
||||
clangBasic
|
||||
)
|
||||
|
||||
set(LLVM_LINK_COMPONENTS
|
||||
jit
|
||||
interpreter
|
||||
nativecodegen
|
||||
asmparser
|
||||
bitreader
|
||||
bitwriter
|
||||
codegen
|
||||
ipo
|
||||
linker
|
||||
selectiondag
|
||||
jit
|
||||
interpreter
|
||||
nativecodegen
|
||||
asmparser
|
||||
bitreader
|
||||
bitwriter
|
||||
codegen
|
||||
ipo
|
||||
linker
|
||||
selectiondag
|
||||
)
|
||||
|
||||
add_clang_executable(clang-interpreter
|
||||
main.cpp
|
||||
)
|
||||
add_dependencies(clang-interpreter clang-headers)
|
||||
|
||||
add_dependencies(clang-interpreter
|
||||
clang-headers
|
||||
)
|
||||
|
||||
target_link_libraries(clang-interpreter
|
||||
clangFrontend
|
||||
clangSerialization
|
||||
clangDriver
|
||||
clangCodeGen
|
||||
clangSema
|
||||
clangStaticAnalyzerFrontend
|
||||
clangStaticAnalyzerCheckers
|
||||
clangStaticAnalyzerCore
|
||||
clangAnalysis
|
||||
clangRewrite
|
||||
clangAST
|
||||
clangParse
|
||||
clangLex
|
||||
clangBasic
|
||||
)
|
||||
|
|
|
|||
146
include/clang-c/CXCompilationDatabase.h
Normal file
146
include/clang-c/CXCompilationDatabase.h
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
/*===-- clang-c/CXCompilationDatabase.h - Compilation database ---*- C -*-===*\
|
||||
|* *|
|
||||
|* The LLVM Compiler Infrastructure *|
|
||||
|* *|
|
||||
|* This file is distributed under the University of Illinois Open Source *|
|
||||
|* License. See LICENSE.TXT for details. *|
|
||||
|* *|
|
||||
|*===----------------------------------------------------------------------===*|
|
||||
|* *|
|
||||
|* This header provides a public inferface to use CompilationDatabase without *|
|
||||
|* the full Clang C++ API. *|
|
||||
|* *|
|
||||
\*===----------------------------------------------------------------------===*/
|
||||
|
||||
#ifndef CLANG_CXCOMPILATIONDATABASE_H
|
||||
#define CLANG_CXCOMPILATIONDATABASE_H
|
||||
|
||||
#include "clang-c/Platform.h"
|
||||
#include "clang-c/CXString.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** \defgroup COMPILATIONDB CompilationDatabase functions
|
||||
* \ingroup CINDEX
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* A compilation database holds all information used to compile files in a
|
||||
* project. For each file in the database, it can be queried for the working
|
||||
* directory or the command line used for the compiler invocation.
|
||||
*
|
||||
* Must be freed by \c clang_CompilationDatabase_dispose
|
||||
*/
|
||||
typedef void * CXCompilationDatabase;
|
||||
|
||||
/**
|
||||
* \brief Contains the results of a search in the compilation database
|
||||
*
|
||||
* When searching for the compile command for a file, the compilation db can
|
||||
* return several commands, as the file may have been compiled with
|
||||
* different options in different places of the project. This choice of compile
|
||||
* commands is wrapped in this opaque data structure. It must be freed by
|
||||
* \c clang_CompileCommands_dispose.
|
||||
*/
|
||||
typedef void * CXCompileCommands;
|
||||
|
||||
/**
|
||||
* \brief Represents the command line invocation to compile a specific file.
|
||||
*/
|
||||
typedef void * CXCompileCommand;
|
||||
|
||||
/**
|
||||
* \brief Error codes for Compilation Database
|
||||
*/
|
||||
typedef enum {
|
||||
/*
|
||||
* \brief No error occured
|
||||
*/
|
||||
CXCompilationDatabase_NoError = 0,
|
||||
|
||||
/*
|
||||
* \brief Database can not be loaded
|
||||
*/
|
||||
CXCompilationDatabase_CanNotLoadDatabase = 1
|
||||
|
||||
} CXCompilationDatabase_Error;
|
||||
|
||||
/**
|
||||
* \brief Creates a compilation database from the database found in directory
|
||||
* buildDir. For example, CMake can output a compile_commands.json which can
|
||||
* be used to build the database.
|
||||
*
|
||||
* It must be freed by \c clang_CompilationDatabase_dispose.
|
||||
*/
|
||||
CINDEX_LINKAGE CXCompilationDatabase
|
||||
clang_CompilationDatabase_fromDirectory(const char *BuildDir,
|
||||
CXCompilationDatabase_Error *ErrorCode);
|
||||
|
||||
/**
|
||||
* \brief Free the given compilation database
|
||||
*/
|
||||
CINDEX_LINKAGE void
|
||||
clang_CompilationDatabase_dispose(CXCompilationDatabase);
|
||||
|
||||
/**
|
||||
* \brief Find the compile commands used for a file. The compile commands
|
||||
* must be freed by \c clang_CompileCommands_dispose.
|
||||
*/
|
||||
CINDEX_LINKAGE CXCompileCommands
|
||||
clang_CompilationDatabase_getCompileCommands(CXCompilationDatabase,
|
||||
const char *CompleteFileName);
|
||||
|
||||
/**
|
||||
* \brief Free the given CompileCommands
|
||||
*/
|
||||
CINDEX_LINKAGE void clang_CompileCommands_dispose(CXCompileCommands);
|
||||
|
||||
/**
|
||||
* \brief Get the number of CompileCommand we have for a file
|
||||
*/
|
||||
CINDEX_LINKAGE unsigned
|
||||
clang_CompileCommands_getSize(CXCompileCommands);
|
||||
|
||||
/**
|
||||
* \brief Get the I'th CompileCommand for a file
|
||||
*
|
||||
* Note : 0 <= i < clang_CompileCommands_getSize(CXCompileCommands)
|
||||
*/
|
||||
CINDEX_LINKAGE CXCompileCommand
|
||||
clang_CompileCommands_getCommand(CXCompileCommands, unsigned I);
|
||||
|
||||
/**
|
||||
* \brief Get the working directory where the CompileCommand was executed from
|
||||
*/
|
||||
CINDEX_LINKAGE CXString
|
||||
clang_CompileCommand_getDirectory(CXCompileCommand);
|
||||
|
||||
/**
|
||||
* \brief Get the number of arguments in the compiler invocation.
|
||||
*
|
||||
*/
|
||||
CINDEX_LINKAGE unsigned
|
||||
clang_CompileCommand_getNumArgs(CXCompileCommand);
|
||||
|
||||
/**
|
||||
* \brief Get the I'th argument value in the compiler invocations
|
||||
*
|
||||
* Invariant :
|
||||
* - argument 0 is the compiler executable
|
||||
*/
|
||||
CINDEX_LINKAGE CXString
|
||||
clang_CompileCommand_getArg(CXCompileCommand, unsigned I);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
61
include/clang-c/CXString.h
Normal file
61
include/clang-c/CXString.h
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
/*===-- clang-c/CXString.h - C Index strings --------------------*- C -*-===*\
|
||||
|* *|
|
||||
|* The LLVM Compiler Infrastructure *|
|
||||
|* *|
|
||||
|* This file is distributed under the University of Illinois Open Source *|
|
||||
|* License. See LICENSE.TXT for details. *|
|
||||
|* *|
|
||||
|*===----------------------------------------------------------------------===*|
|
||||
|* *|
|
||||
|* This header provides the interface to C Index strings. *|
|
||||
|* *|
|
||||
\*===----------------------------------------------------------------------===*/
|
||||
|
||||
#ifndef CLANG_CXSTRING_H
|
||||
#define CLANG_CXSTRING_H
|
||||
|
||||
#include "clang-c/Platform.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \defgroup CINDEX_STRING String manipulation routines
|
||||
* \ingroup CINDEX
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief A character string.
|
||||
*
|
||||
* The \c CXString type is used to return strings from the interface when
|
||||
* the ownership of that string might different from one call to the next.
|
||||
* Use \c clang_getCString() to retrieve the string data and, once finished
|
||||
* with the string data, call \c clang_disposeString() to free the string.
|
||||
*/
|
||||
typedef struct {
|
||||
void *data;
|
||||
unsigned private_flags;
|
||||
} CXString;
|
||||
|
||||
/**
|
||||
* \brief Retrieve the character data associated with the given string.
|
||||
*/
|
||||
CINDEX_LINKAGE const char *clang_getCString(CXString string);
|
||||
|
||||
/**
|
||||
* \brief Free the given string,
|
||||
*/
|
||||
CINDEX_LINKAGE void clang_disposeString(CXString string);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load diff
45
include/clang-c/Platform.h
Normal file
45
include/clang-c/Platform.h
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/*===-- clang-c/Platform.h - C Index platform decls -------------*- C -*-===*\
|
||||
|* *|
|
||||
|* The LLVM Compiler Infrastructure *|
|
||||
|* *|
|
||||
|* This file is distributed under the University of Illinois Open Source *|
|
||||
|* License. See LICENSE.TXT for details. *|
|
||||
|* *|
|
||||
|*===----------------------------------------------------------------------===*|
|
||||
|* *|
|
||||
|* This header provides platform specific macros (dllimport, deprecated, ...) *|
|
||||
|* *|
|
||||
\*===----------------------------------------------------------------------===*/
|
||||
|
||||
#ifndef CLANG_C_PLATFORM_H
|
||||
#define CLANG_C_PLATFORM_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* MSVC DLL import/export. */
|
||||
#ifdef _MSC_VER
|
||||
#ifdef _CINDEX_LIB_
|
||||
#define CINDEX_LINKAGE __declspec(dllexport)
|
||||
#else
|
||||
#define CINDEX_LINKAGE __declspec(dllimport)
|
||||
#endif
|
||||
#else
|
||||
#define CINDEX_LINKAGE
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define CINDEX_DEPRECATED __attribute__((deprecated))
|
||||
#else
|
||||
#ifdef _MSC_VER
|
||||
#define CINDEX_DEPRECATED __declspec(deprecated)
|
||||
#else
|
||||
#define CINDEX_DEPRECATED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
|
@ -27,6 +27,7 @@
|
|||
#include "clang/AST/TemplateName.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/AST/CanonicalType.h"
|
||||
#include "clang/AST/RawCommentList.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
#include "llvm/ADT/IntrusiveRefCntPtr.h"
|
||||
|
|
@ -51,7 +52,6 @@ namespace clang {
|
|||
class ASTMutationListener;
|
||||
class IdentifierTable;
|
||||
class SelectorTable;
|
||||
class SourceManager;
|
||||
class TargetInfo;
|
||||
class CXXABI;
|
||||
// Decls
|
||||
|
|
@ -80,6 +80,10 @@ namespace clang {
|
|||
|
||||
namespace Builtin { class Context; }
|
||||
|
||||
namespace comments {
|
||||
class FullComment;
|
||||
}
|
||||
|
||||
/// ASTContext - This class holds long-lived AST nodes (such as types and
|
||||
/// decls) that can be referred to throughout the semantic analysis of a file.
|
||||
class ASTContext : public RefCountedBase<ASTContext> {
|
||||
|
|
@ -198,10 +202,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
|||
/// \brief The typedef for the __uint128_t type.
|
||||
mutable TypedefDecl *UInt128Decl;
|
||||
|
||||
/// BuiltinVaListType - built-in va list type.
|
||||
/// This is initially null and set by Sema::LazilyCreateBuiltin when
|
||||
/// a builtin that takes a valist is encountered.
|
||||
QualType BuiltinVaListType;
|
||||
/// \brief The typedef for the target specific predefined
|
||||
/// __builtin_va_list type.
|
||||
mutable TypedefDecl *BuiltinVaListDecl;
|
||||
|
||||
/// \brief The typedef for the predefined 'id' type.
|
||||
mutable TypedefDecl *ObjCIdDecl;
|
||||
|
|
@ -392,6 +395,11 @@ public:
|
|||
|
||||
SourceManager& getSourceManager() { return SourceMgr; }
|
||||
const SourceManager& getSourceManager() const { return SourceMgr; }
|
||||
|
||||
llvm::BumpPtrAllocator &getAllocator() const {
|
||||
return BumpAlloc;
|
||||
}
|
||||
|
||||
void *Allocate(unsigned Size, unsigned Align = 8) const {
|
||||
return BumpAlloc.Allocate(Size, Align);
|
||||
}
|
||||
|
|
@ -419,6 +427,85 @@ public:
|
|||
return FullSourceLoc(Loc,SourceMgr);
|
||||
}
|
||||
|
||||
/// \brief All comments in this translation unit.
|
||||
RawCommentList Comments;
|
||||
|
||||
/// \brief True if comments are already loaded from ExternalASTSource.
|
||||
mutable bool CommentsLoaded;
|
||||
|
||||
class RawCommentAndCacheFlags {
|
||||
public:
|
||||
enum Kind {
|
||||
/// We searched for a comment attached to the particular declaration, but
|
||||
/// didn't find any.
|
||||
///
|
||||
/// getRaw() == 0.
|
||||
NoCommentInDecl = 0,
|
||||
|
||||
/// We have found a comment attached to this particular declaration.
|
||||
///
|
||||
/// getRaw() != 0.
|
||||
FromDecl,
|
||||
|
||||
/// This declaration does not have an attached comment, and we have
|
||||
/// searched the redeclaration chain.
|
||||
///
|
||||
/// If getRaw() == 0, the whole redeclaration chain does not have any
|
||||
/// comments.
|
||||
///
|
||||
/// If getRaw() != 0, it is a comment propagated from other
|
||||
/// redeclaration.
|
||||
FromRedecl
|
||||
};
|
||||
|
||||
Kind getKind() const LLVM_READONLY {
|
||||
return Data.getInt();
|
||||
}
|
||||
|
||||
void setKind(Kind K) {
|
||||
Data.setInt(K);
|
||||
}
|
||||
|
||||
const RawComment *getRaw() const LLVM_READONLY {
|
||||
return Data.getPointer();
|
||||
}
|
||||
|
||||
void setRaw(const RawComment *RC) {
|
||||
Data.setPointer(RC);
|
||||
}
|
||||
|
||||
private:
|
||||
llvm::PointerIntPair<const RawComment *, 2, Kind> Data;
|
||||
};
|
||||
|
||||
/// \brief Mapping from declarations to comments attached to any
|
||||
/// redeclaration.
|
||||
///
|
||||
/// Raw comments are owned by Comments list. This mapping is populated
|
||||
/// lazily.
|
||||
mutable llvm::DenseMap<const Decl *, RawCommentAndCacheFlags> RedeclComments;
|
||||
|
||||
/// \brief Return the documentation comment attached to a given declaration,
|
||||
/// without looking into cache.
|
||||
RawComment *getRawCommentForDeclNoCache(const Decl *D) const;
|
||||
|
||||
public:
|
||||
RawCommentList &getRawCommentList() {
|
||||
return Comments;
|
||||
}
|
||||
|
||||
void addComment(const RawComment &RC) {
|
||||
Comments.addComment(RC, BumpAlloc);
|
||||
}
|
||||
|
||||
/// \brief Return the documentation comment attached to a given declaration.
|
||||
/// Returns NULL if no comment is attached.
|
||||
const RawComment *getRawCommentForAnyRedecl(const Decl *D) const;
|
||||
|
||||
/// Return parsed documentation comment attached to a given declaration.
|
||||
/// Returns NULL if no comment is attached.
|
||||
comments::FullComment *getCommentForDecl(const Decl *D) const;
|
||||
|
||||
/// \brief Retrieve the attributes for the given declaration.
|
||||
AttrVec& getDeclAttrs(const Decl *D);
|
||||
|
||||
|
|
@ -557,6 +644,7 @@ public:
|
|||
CanQualType BoolTy;
|
||||
CanQualType CharTy;
|
||||
CanQualType WCharTy; // [C++ 3.9.1p5], integer type in C99.
|
||||
CanQualType WIntTy; // [C99 7.24.1], integer type unchanged by default promotions.
|
||||
CanQualType Char16Ty; // [C++0x 3.9.1p5], integer type in C99.
|
||||
CanQualType Char32Ty; // [C++0x 3.9.1p5], integer type in C99.
|
||||
CanQualType SignedCharTy, ShortTy, IntTy, LongTy, LongLongTy, Int128Ty;
|
||||
|
|
@ -575,6 +663,10 @@ public:
|
|||
mutable QualType AutoDeductTy; // Deduction against 'auto'.
|
||||
mutable QualType AutoRRefDeductTy; // Deduction against 'auto &&'.
|
||||
|
||||
// Type used to help define __builtin_va_list for some targets.
|
||||
// The type is built when constructing 'BuiltinVaListDecl'.
|
||||
mutable QualType VaListTagTy;
|
||||
|
||||
ASTContext(LangOptions& LOpts, SourceManager &SM, const TargetInfo *t,
|
||||
IdentifierTable &idents, SelectorTable &sels,
|
||||
Builtin::Context &builtins,
|
||||
|
|
@ -929,6 +1021,10 @@ public:
|
|||
/// Used when in C++, as a GCC extension.
|
||||
QualType getUnsignedWCharType() const;
|
||||
|
||||
/// getWIntType - In C99, this returns a type compatible with the type
|
||||
/// defined in <stddef.h> as defined by the target.
|
||||
QualType getWIntType() const { return WIntTy; }
|
||||
|
||||
/// getPointerDiffType - Return the unique type for "ptrdiff_t" (C99 7.17)
|
||||
/// defined in <stddef.h>. Pointer - pointer requires this (C99 6.5.6p9).
|
||||
QualType getPointerDiffType() const;
|
||||
|
|
@ -1148,8 +1244,19 @@ public:
|
|||
return getObjCInterfaceType(getObjCProtocolDecl());
|
||||
}
|
||||
|
||||
void setBuiltinVaListType(QualType T);
|
||||
QualType getBuiltinVaListType() const { return BuiltinVaListType; }
|
||||
/// \brief Retrieve the C type declaration corresponding to the predefined
|
||||
/// __builtin_va_list type.
|
||||
TypedefDecl *getBuiltinVaListDecl() const;
|
||||
|
||||
/// \brief Retrieve the type of the __builtin_va_list type.
|
||||
QualType getBuiltinVaListType() const {
|
||||
return getTypeDeclType(getBuiltinVaListDecl());
|
||||
}
|
||||
|
||||
/// \brief Retrieve the C type declaration corresponding to the predefined
|
||||
/// __va_list_tag type used to help define the __builtin_va_list type for
|
||||
/// some targets.
|
||||
QualType getVaListTagType() const;
|
||||
|
||||
/// getCVRQualifiedType - Returns a type with additional const,
|
||||
/// volatile, or restrict qualifiers.
|
||||
|
|
@ -1210,10 +1317,10 @@ public:
|
|||
const TemplateArgument &ArgPack) const;
|
||||
|
||||
enum GetBuiltinTypeError {
|
||||
GE_None, //< No error
|
||||
GE_Missing_stdio, //< Missing a type from <stdio.h>
|
||||
GE_Missing_setjmp, //< Missing a type from <setjmp.h>
|
||||
GE_Missing_ucontext //< Missing a type from <ucontext.h>
|
||||
GE_None, ///< No error
|
||||
GE_Missing_stdio, ///< Missing a type from <stdio.h>
|
||||
GE_Missing_setjmp, ///< Missing a type from <setjmp.h>
|
||||
GE_Missing_ucontext ///< Missing a type from <ucontext.h>
|
||||
};
|
||||
|
||||
/// GetBuiltinType - Return the type for the specified builtin. If
|
||||
|
|
@ -1440,15 +1547,11 @@ public:
|
|||
|
||||
/// \brief Retrieves the default calling convention to use for
|
||||
/// C++ instance methods.
|
||||
CallingConv getDefaultMethodCallConv();
|
||||
CallingConv getDefaultCXXMethodCallConv(bool isVariadic);
|
||||
|
||||
/// \brief Retrieves the canonical representation of the given
|
||||
/// calling convention.
|
||||
CallingConv getCanonicalCallConv(CallingConv CC) const {
|
||||
if (!LangOpts.MRTD && CC == CC_C)
|
||||
return CC_Default;
|
||||
return CC;
|
||||
}
|
||||
CallingConv getCanonicalCallConv(CallingConv CC) const;
|
||||
|
||||
/// \brief Determines whether two calling conventions name the same
|
||||
/// calling convention.
|
||||
|
|
@ -1463,7 +1566,7 @@ public:
|
|||
/// be used to refer to a given template. For most templates, this
|
||||
/// expression is just the template declaration itself. For example,
|
||||
/// the template std::vector can be referred to via a variety of
|
||||
/// names---std::vector, ::std::vector, vector (if vector is in
|
||||
/// names---std::vector, \::std::vector, vector (if vector is in
|
||||
/// scope), etc.---but all of these names map down to the same
|
||||
/// TemplateDecl, which is used to form the canonical template name.
|
||||
///
|
||||
|
|
@ -1523,12 +1626,12 @@ public:
|
|||
/// This routine adjusts the given parameter type @p T to the actual
|
||||
/// parameter type used by semantic analysis (C99 6.7.5.3p[7,8],
|
||||
/// C++ [dcl.fct]p3). The adjusted parameter type is returned.
|
||||
QualType getAdjustedParameterType(QualType T);
|
||||
QualType getAdjustedParameterType(QualType T) const;
|
||||
|
||||
/// \brief Retrieve the parameter type as adjusted for use in the signature
|
||||
/// of a function, decaying array and function types and removing top-level
|
||||
/// cv-qualifiers.
|
||||
QualType getSignatureParameterType(QualType T);
|
||||
QualType getSignatureParameterType(QualType T) const;
|
||||
|
||||
/// getArrayDecayedType - Return the properly qualified result of decaying the
|
||||
/// specified array type to a pointer. This operation is non-trivial when
|
||||
|
|
@ -1700,7 +1803,7 @@ public:
|
|||
/// \brief Get the implementation of ObjCCategoryDecl, or NULL if none exists.
|
||||
ObjCCategoryImplDecl *getObjCImplementation(ObjCCategoryDecl *D);
|
||||
|
||||
/// \brief returns true if there is at lease one @implementation in TU.
|
||||
/// \brief returns true if there is at least one \@implementation in TU.
|
||||
bool AnyObjCImplementation() {
|
||||
return !ObjCImpls.empty();
|
||||
}
|
||||
|
|
@ -1716,15 +1819,12 @@ public:
|
|||
/// interface, or null if non exists.
|
||||
const ObjCMethodDecl *getObjCMethodRedeclaration(
|
||||
const ObjCMethodDecl *MD) const {
|
||||
llvm::DenseMap<const ObjCMethodDecl*, const ObjCMethodDecl*>::const_iterator
|
||||
I = ObjCMethodRedecls.find(MD);
|
||||
if (I == ObjCMethodRedecls.end())
|
||||
return 0;
|
||||
return I->second;
|
||||
return ObjCMethodRedecls.lookup(MD);
|
||||
}
|
||||
|
||||
void setObjCMethodRedeclaration(const ObjCMethodDecl *MD,
|
||||
const ObjCMethodDecl *Redecl) {
|
||||
assert(!getObjCMethodRedeclaration(MD) && "MD already has a redeclaration");
|
||||
ObjCMethodRedecls[MD] = Redecl;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -271,7 +271,8 @@ namespace clang {
|
|||
|
||||
/// \brief Determine whether the given types are structurally
|
||||
/// equivalent.
|
||||
bool IsStructurallyEquivalent(QualType From, QualType To);
|
||||
bool IsStructurallyEquivalent(QualType From, QualType To,
|
||||
bool Complain = true);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -374,7 +374,7 @@ void ASTVector<T>::grow(ASTContext &C, size_t MinSize) {
|
|||
NewCapacity = MinSize;
|
||||
|
||||
// Allocate the memory from the ASTContext.
|
||||
T *NewElts = new (C) T[NewCapacity];
|
||||
T *NewElts = new (C, llvm::alignOf<T>()) T[NewCapacity];
|
||||
|
||||
// Copy the elements over.
|
||||
if (llvm::is_class<T>::value) {
|
||||
|
|
@ -387,7 +387,7 @@ void ASTVector<T>::grow(ASTContext &C, size_t MinSize) {
|
|||
memcpy(NewElts, Begin, CurSize * sizeof(T));
|
||||
}
|
||||
|
||||
C.Deallocate(Begin);
|
||||
// ASTContext never frees any memory.
|
||||
Begin = NewElts;
|
||||
End = NewElts+CurSize;
|
||||
Capacity = Begin+NewCapacity;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
//===--- Attr.h - Classes for representing expressions ----------*- C++ -*-===//
|
||||
//===--- Attr.h - Classes for representing attributes ----------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
|
|
@ -147,14 +147,12 @@ public:
|
|||
typedef SmallVector<Attr*, 2> AttrVec;
|
||||
typedef SmallVector<const Attr*, 2> ConstAttrVec;
|
||||
|
||||
/// DestroyAttrs - Destroy the contents of an AttrVec.
|
||||
inline void DestroyAttrs (AttrVec& V, ASTContext &C) {
|
||||
}
|
||||
|
||||
/// specific_attr_iterator - Iterates over a subrange of an AttrVec, only
|
||||
/// providing attributes that are of a specifc type.
|
||||
template <typename SpecificAttr>
|
||||
template <typename SpecificAttr, typename Container = AttrVec>
|
||||
class specific_attr_iterator {
|
||||
typedef typename Container::const_iterator Iterator;
|
||||
|
||||
/// Current - The current, underlying iterator.
|
||||
/// In order to ensure we don't dereference an invalid iterator unless
|
||||
/// specifically requested, we don't necessarily advance this all the
|
||||
|
|
@ -162,14 +160,14 @@ class specific_attr_iterator {
|
|||
/// operation is acting on what should be a past-the-end iterator,
|
||||
/// then we offer no guarantees, but this way we do not dererence a
|
||||
/// past-the-end iterator when we move to a past-the-end position.
|
||||
mutable AttrVec::const_iterator Current;
|
||||
mutable Iterator Current;
|
||||
|
||||
void AdvanceToNext() const {
|
||||
while (!isa<SpecificAttr>(*Current))
|
||||
++Current;
|
||||
}
|
||||
|
||||
void AdvanceToNext(AttrVec::const_iterator I) const {
|
||||
void AdvanceToNext(Iterator I) const {
|
||||
while (Current != I && !isa<SpecificAttr>(*Current))
|
||||
++Current;
|
||||
}
|
||||
|
|
@ -182,7 +180,7 @@ public:
|
|||
typedef std::ptrdiff_t difference_type;
|
||||
|
||||
specific_attr_iterator() : Current() { }
|
||||
explicit specific_attr_iterator(AttrVec::const_iterator i) : Current(i) { }
|
||||
explicit specific_attr_iterator(Iterator i) : Current(i) { }
|
||||
|
||||
reference operator*() const {
|
||||
AdvanceToNext();
|
||||
|
|
@ -217,23 +215,27 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
inline specific_attr_iterator<T> specific_attr_begin(const AttrVec& vec) {
|
||||
return specific_attr_iterator<T>(vec.begin());
|
||||
template <typename SpecificAttr, typename Container>
|
||||
inline specific_attr_iterator<SpecificAttr, Container>
|
||||
specific_attr_begin(const Container& container) {
|
||||
return specific_attr_iterator<SpecificAttr, Container>(container.begin());
|
||||
}
|
||||
template <typename T>
|
||||
inline specific_attr_iterator<T> specific_attr_end(const AttrVec& vec) {
|
||||
return specific_attr_iterator<T>(vec.end());
|
||||
template <typename SpecificAttr, typename Container>
|
||||
inline specific_attr_iterator<SpecificAttr, Container>
|
||||
specific_attr_end(const Container& container) {
|
||||
return specific_attr_iterator<SpecificAttr, Container>(container.end());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline bool hasSpecificAttr(const AttrVec& vec) {
|
||||
return specific_attr_begin<T>(vec) != specific_attr_end<T>(vec);
|
||||
template <typename SpecificAttr, typename Container>
|
||||
inline bool hasSpecificAttr(const Container& container) {
|
||||
return specific_attr_begin<SpecificAttr>(container) !=
|
||||
specific_attr_end<SpecificAttr>(container);
|
||||
}
|
||||
template <typename T>
|
||||
inline T *getSpecificAttr(const AttrVec& vec) {
|
||||
specific_attr_iterator<T> i = specific_attr_begin<T>(vec);
|
||||
if (i != specific_attr_end<T>(vec))
|
||||
template <typename SpecificAttr, typename Container>
|
||||
inline SpecificAttr *getSpecificAttr(const Container& container) {
|
||||
specific_attr_iterator<SpecificAttr, Container> i =
|
||||
specific_attr_begin<SpecificAttr>(container);
|
||||
if (i != specific_attr_end<SpecificAttr>(container))
|
||||
return *i;
|
||||
else
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -66,9 +66,9 @@ template<> struct DenseMapInfo<clang::BaseSubobject> {
|
|||
}
|
||||
|
||||
static unsigned getHashValue(const clang::BaseSubobject &Base) {
|
||||
return
|
||||
DenseMapInfo<const clang::CXXRecordDecl *>::getHashValue(Base.getBase()) ^
|
||||
DenseMapInfo<int64_t>::getHashValue(Base.getBaseOffset().getQuantity());
|
||||
typedef std::pair<const clang::CXXRecordDecl *, clang::CharUnits> PairTy;
|
||||
return DenseMapInfo<PairTy>::getHashValue(PairTy(Base.getBase(),
|
||||
Base.getBaseOffset()));
|
||||
}
|
||||
|
||||
static bool isEqual(const clang::BaseSubobject &LHS,
|
||||
|
|
|
|||
|
|
@ -15,3 +15,8 @@ clang_tablegen(StmtNodes.inc -gen-clang-stmt-nodes
|
|||
clang_tablegen(DeclNodes.inc -gen-clang-decl-nodes
|
||||
SOURCE ../Basic/DeclNodes.td
|
||||
TARGET ClangDeclNodes)
|
||||
|
||||
clang_tablegen(CommentNodes.inc -gen-clang-comment-nodes
|
||||
SOURCE ../Basic/CommentNodes.td
|
||||
TARGET ClangCommentNodes)
|
||||
|
||||
|
|
|
|||
|
|
@ -128,8 +128,7 @@ class CXXBasePaths {
|
|||
/// while the element contains the number of non-virtual base
|
||||
/// class subobjects for that class type. The key of the map is
|
||||
/// the cv-unqualified canonical type of the base class subobject.
|
||||
std::map<QualType, std::pair<bool, unsigned>, QualTypeOrdering>
|
||||
ClassSubobjects;
|
||||
llvm::SmallDenseMap<QualType, std::pair<bool, unsigned>, 8> ClassSubobjects;
|
||||
|
||||
/// FindAmbiguities - Whether Sema::IsDerivedFrom should try find
|
||||
/// ambiguous paths while it is looking for a path from a derived
|
||||
|
|
|
|||
1059
include/clang/AST/Comment.h
Normal file
1059
include/clang/AST/Comment.h
Normal file
File diff suppressed because it is too large
Load diff
56
include/clang/AST/CommentBriefParser.h
Normal file
56
include/clang/AST/CommentBriefParser.h
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
//===--- CommentBriefParser.h - Dumb comment parser -------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines a very simple Doxygen comment parser.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
|
||||
#ifndef LLVM_CLANG_AST_BRIEF_COMMENT_PARSER_H
|
||||
#define LLVM_CLANG_AST_BRIEF_COMMENT_PARSER_H
|
||||
|
||||
#include "clang/AST/CommentLexer.h"
|
||||
|
||||
namespace clang {
|
||||
namespace comments {
|
||||
|
||||
/// A very simple comment parser that extracts "a brief description".
|
||||
///
|
||||
/// Due to a variety of comment styles, it considers the following as "a brief
|
||||
/// description", in order of priority:
|
||||
/// \li a \\brief or \\short command,
|
||||
/// \li the first paragraph,
|
||||
/// \li a \\result or \\return or \\returns paragraph.
|
||||
class BriefParser {
|
||||
Lexer &L;
|
||||
|
||||
const CommandTraits &Traits;
|
||||
|
||||
/// Current lookahead token.
|
||||
Token Tok;
|
||||
|
||||
SourceLocation ConsumeToken() {
|
||||
SourceLocation Loc = Tok.getLocation();
|
||||
L.lex(Tok);
|
||||
return Loc;
|
||||
}
|
||||
|
||||
public:
|
||||
BriefParser(Lexer &L, const CommandTraits &Traits);
|
||||
|
||||
/// Return \\brief paragraph, if it exists; otherwise return the first
|
||||
/// paragraph.
|
||||
std::string Parse();
|
||||
};
|
||||
|
||||
} // end namespace comments
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
|
||||
156
include/clang/AST/CommentCommandTraits.h
Normal file
156
include/clang/AST/CommentCommandTraits.h
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
//===--- CommentCommandTraits.h - Comment command properties ----*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the class that provides information about comment
|
||||
// commands.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
|
||||
#ifndef LLVM_CLANG_AST_COMMENT_COMMAND_TRAITS_H
|
||||
#define LLVM_CLANG_AST_COMMENT_COMMAND_TRAITS_H
|
||||
|
||||
#include "clang/Basic/LLVM.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringSwitch.h"
|
||||
|
||||
namespace clang {
|
||||
namespace comments {
|
||||
|
||||
/// This class provides informaiton about commands that can be used
|
||||
/// in comments.
|
||||
class CommandTraits {
|
||||
public:
|
||||
CommandTraits() { }
|
||||
|
||||
/// \brief Check if a given 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 BeginName 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;
|
||||
|
||||
/// \brief Register a new verbatim block command.
|
||||
void addVerbatimBlockCommand(StringRef BeginName, StringRef EndName);
|
||||
|
||||
/// \brief Check if a given 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;
|
||||
|
||||
/// \brief Check if a given command is a command that contains a declaration
|
||||
/// for the entity being documented.
|
||||
///
|
||||
/// For example:
|
||||
/// \code
|
||||
/// \fn void f(int a);
|
||||
/// \endcode
|
||||
bool isDeclarationCommand(StringRef Name) const;
|
||||
|
||||
/// \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 BeginName;
|
||||
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;
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
inline bool CommandTraits::isParamCommand(StringRef Name) const {
|
||||
return Name == "param";
|
||||
}
|
||||
|
||||
inline bool CommandTraits::isTParamCommand(StringRef Name) const {
|
||||
return Name == "tparam" || // Doxygen
|
||||
Name == "templatefield"; // HeaderDoc
|
||||
}
|
||||
|
||||
inline bool CommandTraits::isBriefCommand(StringRef Name) const {
|
||||
return Name == "brief" || Name == "short";
|
||||
}
|
||||
|
||||
inline bool CommandTraits::isReturnsCommand(StringRef Name) const {
|
||||
return Name == "returns" || Name == "return" || Name == "result";
|
||||
}
|
||||
|
||||
inline unsigned CommandTraits::getBlockCommandNumArgs(StringRef Name) const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
} // end namespace comments
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
|
||||
29
include/clang/AST/CommentDiagnostic.h
Normal file
29
include/clang/AST/CommentDiagnostic.h
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
//===--- CommentDiagnostic.h - Diagnostics for the AST library --*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_COMMENTDIAGNOSTIC_H
|
||||
#define LLVM_CLANG_COMMENTDIAGNOSTIC_H
|
||||
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
|
||||
namespace clang {
|
||||
namespace diag {
|
||||
enum {
|
||||
#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\
|
||||
SFINAE,ACCESS,NOWERROR,SHOWINSYSHEADER,CATEGORY) ENUM,
|
||||
#define COMMENTSTART
|
||||
#include "clang/Basic/DiagnosticCommentKinds.inc"
|
||||
#undef DIAG
|
||||
NUM_BUILTIN_COMMENT_DIAGNOSTICS
|
||||
};
|
||||
} // end namespace diag
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
|
||||
353
include/clang/AST/CommentLexer.h
Normal file
353
include/clang/AST/CommentLexer.h
Normal file
|
|
@ -0,0 +1,353 @@
|
|||
//===--- CommentLexer.h - Lexer for structured comments ---------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines lexer for structured comments and supporting token class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_COMMENT_LEXER_H
|
||||
#define LLVM_CLANG_AST_COMMENT_LEXER_H
|
||||
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
namespace clang {
|
||||
namespace comments {
|
||||
|
||||
class Lexer;
|
||||
class TextTokenRetokenizer;
|
||||
class CommandTraits;
|
||||
|
||||
namespace tok {
|
||||
enum TokenKind {
|
||||
eof,
|
||||
newline,
|
||||
text,
|
||||
command,
|
||||
verbatim_block_begin,
|
||||
verbatim_block_line,
|
||||
verbatim_block_end,
|
||||
verbatim_line_name,
|
||||
verbatim_line_text,
|
||||
html_start_tag, // <tag
|
||||
html_ident, // attr
|
||||
html_equals, // =
|
||||
html_quoted_string, // "blah\"blah" or 'blah\'blah'
|
||||
html_greater, // >
|
||||
html_slash_greater, // />
|
||||
html_end_tag // </tag
|
||||
};
|
||||
} // end namespace tok
|
||||
|
||||
class CommentOptions {
|
||||
public:
|
||||
bool Markdown;
|
||||
};
|
||||
|
||||
/// \brief Comment token.
|
||||
class Token {
|
||||
friend class Lexer;
|
||||
friend class TextTokenRetokenizer;
|
||||
|
||||
/// The location of the token.
|
||||
SourceLocation Loc;
|
||||
|
||||
/// The actual kind of the token.
|
||||
tok::TokenKind Kind;
|
||||
|
||||
/// Length of the token spelling in comment. Can be 0 for synthenized
|
||||
/// tokens.
|
||||
unsigned Length;
|
||||
|
||||
/// Contains text value associated with a token.
|
||||
const char *TextPtr1;
|
||||
unsigned TextLen1;
|
||||
|
||||
public:
|
||||
SourceLocation getLocation() const LLVM_READONLY { return Loc; }
|
||||
void setLocation(SourceLocation SL) { Loc = SL; }
|
||||
|
||||
SourceLocation getEndLocation() const LLVM_READONLY {
|
||||
if (Length == 0 || Length == 1)
|
||||
return Loc;
|
||||
return Loc.getLocWithOffset(Length - 1);
|
||||
}
|
||||
|
||||
tok::TokenKind getKind() const LLVM_READONLY { return Kind; }
|
||||
void setKind(tok::TokenKind K) { Kind = K; }
|
||||
|
||||
bool is(tok::TokenKind K) const LLVM_READONLY { return Kind == K; }
|
||||
bool isNot(tok::TokenKind K) const LLVM_READONLY { return Kind != K; }
|
||||
|
||||
unsigned getLength() const LLVM_READONLY { return Length; }
|
||||
void setLength(unsigned L) { Length = L; }
|
||||
|
||||
StringRef getText() const LLVM_READONLY {
|
||||
assert(is(tok::text));
|
||||
return StringRef(TextPtr1, TextLen1);
|
||||
}
|
||||
|
||||
void setText(StringRef Text) {
|
||||
assert(is(tok::text));
|
||||
TextPtr1 = Text.data();
|
||||
TextLen1 = Text.size();
|
||||
}
|
||||
|
||||
StringRef getCommandName() const LLVM_READONLY {
|
||||
assert(is(tok::command));
|
||||
return StringRef(TextPtr1, TextLen1);
|
||||
}
|
||||
|
||||
void setCommandName(StringRef Name) {
|
||||
assert(is(tok::command));
|
||||
TextPtr1 = Name.data();
|
||||
TextLen1 = Name.size();
|
||||
}
|
||||
|
||||
StringRef getVerbatimBlockName() const LLVM_READONLY {
|
||||
assert(is(tok::verbatim_block_begin) || is(tok::verbatim_block_end));
|
||||
return StringRef(TextPtr1, TextLen1);
|
||||
}
|
||||
|
||||
void setVerbatimBlockName(StringRef Name) {
|
||||
assert(is(tok::verbatim_block_begin) || is(tok::verbatim_block_end));
|
||||
TextPtr1 = Name.data();
|
||||
TextLen1 = Name.size();
|
||||
}
|
||||
|
||||
StringRef getVerbatimBlockText() const LLVM_READONLY {
|
||||
assert(is(tok::verbatim_block_line));
|
||||
return StringRef(TextPtr1, TextLen1);
|
||||
}
|
||||
|
||||
void setVerbatimBlockText(StringRef Text) {
|
||||
assert(is(tok::verbatim_block_line));
|
||||
TextPtr1 = Text.data();
|
||||
TextLen1 = Text.size();
|
||||
}
|
||||
|
||||
/// Returns the name of verbatim line command.
|
||||
StringRef getVerbatimLineName() const LLVM_READONLY {
|
||||
assert(is(tok::verbatim_line_name));
|
||||
return StringRef(TextPtr1, TextLen1);
|
||||
}
|
||||
|
||||
void setVerbatimLineName(StringRef Name) {
|
||||
assert(is(tok::verbatim_line_name));
|
||||
TextPtr1 = Name.data();
|
||||
TextLen1 = Name.size();
|
||||
}
|
||||
|
||||
StringRef getVerbatimLineText() const LLVM_READONLY {
|
||||
assert(is(tok::verbatim_line_text));
|
||||
return StringRef(TextPtr1, TextLen1);
|
||||
}
|
||||
|
||||
void setVerbatimLineText(StringRef Text) {
|
||||
assert(is(tok::verbatim_line_text));
|
||||
TextPtr1 = Text.data();
|
||||
TextLen1 = Text.size();
|
||||
}
|
||||
|
||||
StringRef getHTMLTagStartName() const LLVM_READONLY {
|
||||
assert(is(tok::html_start_tag));
|
||||
return StringRef(TextPtr1, TextLen1);
|
||||
}
|
||||
|
||||
void setHTMLTagStartName(StringRef Name) {
|
||||
assert(is(tok::html_start_tag));
|
||||
TextPtr1 = Name.data();
|
||||
TextLen1 = Name.size();
|
||||
}
|
||||
|
||||
StringRef getHTMLIdent() const LLVM_READONLY {
|
||||
assert(is(tok::html_ident));
|
||||
return StringRef(TextPtr1, TextLen1);
|
||||
}
|
||||
|
||||
void setHTMLIdent(StringRef Name) {
|
||||
assert(is(tok::html_ident));
|
||||
TextPtr1 = Name.data();
|
||||
TextLen1 = Name.size();
|
||||
}
|
||||
|
||||
StringRef getHTMLQuotedString() const LLVM_READONLY {
|
||||
assert(is(tok::html_quoted_string));
|
||||
return StringRef(TextPtr1, TextLen1);
|
||||
}
|
||||
|
||||
void setHTMLQuotedString(StringRef Str) {
|
||||
assert(is(tok::html_quoted_string));
|
||||
TextPtr1 = Str.data();
|
||||
TextLen1 = Str.size();
|
||||
}
|
||||
|
||||
StringRef getHTMLTagEndName() const LLVM_READONLY {
|
||||
assert(is(tok::html_end_tag));
|
||||
return StringRef(TextPtr1, TextLen1);
|
||||
}
|
||||
|
||||
void setHTMLTagEndName(StringRef Name) {
|
||||
assert(is(tok::html_end_tag));
|
||||
TextPtr1 = Name.data();
|
||||
TextLen1 = Name.size();
|
||||
}
|
||||
|
||||
void dump(const Lexer &L, const SourceManager &SM) const;
|
||||
};
|
||||
|
||||
/// \brief Comment lexer.
|
||||
class Lexer {
|
||||
private:
|
||||
Lexer(const Lexer&); // DO NOT IMPLEMENT
|
||||
void operator=(const Lexer&); // DO NOT IMPLEMENT
|
||||
|
||||
/// Allocator for strings that are semantic values of tokens and have to be
|
||||
/// computed (for example, resolved decimal character references).
|
||||
llvm::BumpPtrAllocator &Allocator;
|
||||
|
||||
const CommandTraits &Traits;
|
||||
|
||||
const char *const BufferStart;
|
||||
const char *const BufferEnd;
|
||||
SourceLocation FileLoc;
|
||||
CommentOptions CommOpts;
|
||||
|
||||
const char *BufferPtr;
|
||||
|
||||
/// One past end pointer for the current comment. For BCPL comments points
|
||||
/// to newline or BufferEnd, for C comments points to star in '*/'.
|
||||
const char *CommentEnd;
|
||||
|
||||
enum LexerCommentState {
|
||||
LCS_BeforeComment,
|
||||
LCS_InsideBCPLComment,
|
||||
LCS_InsideCComment,
|
||||
LCS_BetweenComments
|
||||
};
|
||||
|
||||
/// Low-level lexer state, track if we are inside or outside of comment.
|
||||
LexerCommentState CommentState;
|
||||
|
||||
enum LexerState {
|
||||
/// Lexing normal comment text
|
||||
LS_Normal,
|
||||
|
||||
/// Finished lexing verbatim block beginning command, will lex first body
|
||||
/// line.
|
||||
LS_VerbatimBlockFirstLine,
|
||||
|
||||
/// Lexing verbatim block body line-by-line, skipping line-starting
|
||||
/// decorations.
|
||||
LS_VerbatimBlockBody,
|
||||
|
||||
/// Finished lexing verbatim line beginning command, will lex text (one
|
||||
/// line).
|
||||
LS_VerbatimLineText,
|
||||
|
||||
/// Finished lexing \verbatim <TAG \endverbatim part, lexing tag attributes.
|
||||
LS_HTMLStartTag,
|
||||
|
||||
/// Finished lexing \verbatim </TAG \endverbatim part, lexing '>'.
|
||||
LS_HTMLEndTag
|
||||
};
|
||||
|
||||
/// Current lexing mode.
|
||||
LexerState State;
|
||||
|
||||
/// If State is LS_VerbatimBlock, contains the name of verbatim end
|
||||
/// command, including command marker.
|
||||
SmallString<16> VerbatimBlockEndCommandName;
|
||||
|
||||
/// Given a character reference name (e.g., "lt"), return the character that
|
||||
/// it stands for (e.g., "<").
|
||||
StringRef resolveHTMLNamedCharacterReference(StringRef Name) const;
|
||||
|
||||
/// Given a Unicode codepoint as base-10 integer, return the character.
|
||||
StringRef resolveHTMLDecimalCharacterReference(StringRef Name) const;
|
||||
|
||||
/// Given a Unicode codepoint as base-16 integer, return the character.
|
||||
StringRef resolveHTMLHexCharacterReference(StringRef Name) const;
|
||||
|
||||
void formTokenWithChars(Token &Result, const char *TokEnd,
|
||||
tok::TokenKind Kind) {
|
||||
const unsigned TokLen = TokEnd - BufferPtr;
|
||||
Result.setLocation(getSourceLocation(BufferPtr));
|
||||
Result.setKind(Kind);
|
||||
Result.setLength(TokLen);
|
||||
#ifndef NDEBUG
|
||||
Result.TextPtr1 = "<UNSET>";
|
||||
Result.TextLen1 = 7;
|
||||
#endif
|
||||
BufferPtr = TokEnd;
|
||||
}
|
||||
|
||||
void formTextToken(Token &Result, const char *TokEnd) {
|
||||
StringRef Text(BufferPtr, TokEnd - BufferPtr);
|
||||
formTokenWithChars(Result, TokEnd, tok::text);
|
||||
Result.setText(Text);
|
||||
}
|
||||
|
||||
SourceLocation getSourceLocation(const char *Loc) const {
|
||||
assert(Loc >= BufferStart && Loc <= BufferEnd &&
|
||||
"Location out of range for this buffer!");
|
||||
|
||||
const unsigned CharNo = Loc - BufferStart;
|
||||
return FileLoc.getLocWithOffset(CharNo);
|
||||
}
|
||||
|
||||
/// Eat string matching regexp \code \s*\* \endcode.
|
||||
void skipLineStartingDecorations();
|
||||
|
||||
/// Lex stuff inside comments. CommentEnd should be set correctly.
|
||||
void lexCommentText(Token &T);
|
||||
|
||||
void setupAndLexVerbatimBlock(Token &T,
|
||||
const char *TextBegin,
|
||||
char Marker, StringRef EndName);
|
||||
|
||||
void lexVerbatimBlockFirstLine(Token &T);
|
||||
|
||||
void lexVerbatimBlockBody(Token &T);
|
||||
|
||||
void setupAndLexVerbatimLine(Token &T, const char *TextBegin);
|
||||
|
||||
void lexVerbatimLineText(Token &T);
|
||||
|
||||
void lexHTMLCharacterReference(Token &T);
|
||||
|
||||
void setupAndLexHTMLStartTag(Token &T);
|
||||
|
||||
void lexHTMLStartTag(Token &T);
|
||||
|
||||
void setupAndLexHTMLEndTag(Token &T);
|
||||
|
||||
void lexHTMLEndTag(Token &T);
|
||||
|
||||
public:
|
||||
Lexer(llvm::BumpPtrAllocator &Allocator, const CommandTraits &Traits,
|
||||
SourceLocation FileLoc, const CommentOptions &CommOpts,
|
||||
const char *BufferStart, const char *BufferEnd);
|
||||
|
||||
void lex(Token &T);
|
||||
|
||||
StringRef getSpelling(const Token &Tok,
|
||||
const SourceManager &SourceMgr,
|
||||
bool *Invalid = NULL) const;
|
||||
};
|
||||
|
||||
} // end namespace comments
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
|
||||
124
include/clang/AST/CommentParser.h
Normal file
124
include/clang/AST/CommentParser.h
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
//===--- CommentParser.h - Doxygen comment parser ---------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the Doxygen comment parser.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_COMMENT_PARSER_H
|
||||
#define LLVM_CLANG_AST_COMMENT_PARSER_H
|
||||
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
#include "clang/AST/CommentLexer.h"
|
||||
#include "clang/AST/Comment.h"
|
||||
#include "clang/AST/CommentSema.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
|
||||
namespace clang {
|
||||
class SourceManager;
|
||||
|
||||
namespace comments {
|
||||
class CommandTraits;
|
||||
|
||||
/// Doxygen comment parser.
|
||||
class Parser {
|
||||
Parser(const Parser&); // DO NOT IMPLEMENT
|
||||
void operator=(const Parser&); // DO NOT IMPLEMENT
|
||||
|
||||
friend class TextTokenRetokenizer;
|
||||
|
||||
Lexer &L;
|
||||
|
||||
Sema &S;
|
||||
|
||||
/// Allocator for anything that goes into AST nodes.
|
||||
llvm::BumpPtrAllocator &Allocator;
|
||||
|
||||
/// Source manager for the comment being parsed.
|
||||
const SourceManager &SourceMgr;
|
||||
|
||||
DiagnosticsEngine &Diags;
|
||||
|
||||
DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID) {
|
||||
return Diags.Report(Loc, DiagID);
|
||||
}
|
||||
|
||||
const CommandTraits &Traits;
|
||||
|
||||
/// Current lookahead token. We can safely assume that all tokens are from
|
||||
/// a single source file.
|
||||
Token Tok;
|
||||
|
||||
/// A stack of additional lookahead tokens.
|
||||
SmallVector<Token, 8> MoreLATokens;
|
||||
|
||||
void consumeToken() {
|
||||
if (MoreLATokens.empty())
|
||||
L.lex(Tok);
|
||||
else {
|
||||
Tok = MoreLATokens.back();
|
||||
MoreLATokens.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
void putBack(const Token &OldTok) {
|
||||
MoreLATokens.push_back(Tok);
|
||||
Tok = OldTok;
|
||||
}
|
||||
|
||||
void putBack(ArrayRef<Token> Toks) {
|
||||
if (Toks.empty())
|
||||
return;
|
||||
|
||||
MoreLATokens.push_back(Tok);
|
||||
for (const Token *I = &Toks.back(),
|
||||
*B = &Toks.front();
|
||||
I != B; --I) {
|
||||
MoreLATokens.push_back(*I);
|
||||
}
|
||||
|
||||
Tok = Toks[0];
|
||||
}
|
||||
|
||||
public:
|
||||
Parser(Lexer &L, Sema &S, llvm::BumpPtrAllocator &Allocator,
|
||||
const SourceManager &SourceMgr, DiagnosticsEngine &Diags,
|
||||
const CommandTraits &Traits);
|
||||
|
||||
/// Parse arguments for \\param command.
|
||||
void parseParamCommandArgs(ParamCommandComment *PC,
|
||||
TextTokenRetokenizer &Retokenizer);
|
||||
|
||||
/// Parse arguments for \\tparam command.
|
||||
void parseTParamCommandArgs(TParamCommandComment *TPC,
|
||||
TextTokenRetokenizer &Retokenizer);
|
||||
|
||||
void parseBlockCommandArgs(BlockCommandComment *BC,
|
||||
TextTokenRetokenizer &Retokenizer,
|
||||
unsigned NumArgs);
|
||||
|
||||
BlockCommandComment *parseBlockCommand();
|
||||
InlineCommandComment *parseInlineCommand();
|
||||
|
||||
HTMLStartTagComment *parseHTMLStartTag();
|
||||
HTMLEndTagComment *parseHTMLEndTag();
|
||||
|
||||
BlockContentComment *parseParagraphOrBlockCommand();
|
||||
|
||||
VerbatimBlockComment *parseVerbatimBlock();
|
||||
VerbatimLineComment *parseVerbatimLine();
|
||||
BlockContentComment *parseBlockContent();
|
||||
FullComment *parseFullComment();
|
||||
};
|
||||
|
||||
} // end namespace comments
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
|
||||
230
include/clang/AST/CommentSema.h
Normal file
230
include/clang/AST/CommentSema.h
Normal file
|
|
@ -0,0 +1,230 @@
|
|||
//===--- CommentSema.h - Doxygen comment semantic analysis ------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the semantic analysis class for Doxygen comments.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_COMMENT_SEMA_H
|
||||
#define LLVM_CLANG_AST_COMMENT_SEMA_H
|
||||
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "clang/AST/Comment.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
|
||||
namespace clang {
|
||||
class Decl;
|
||||
class SourceMgr;
|
||||
|
||||
namespace comments {
|
||||
class CommandTraits;
|
||||
|
||||
class Sema {
|
||||
Sema(const Sema&); // DO NOT IMPLEMENT
|
||||
void operator=(const Sema&); // DO NOT IMPLEMENT
|
||||
|
||||
/// Allocator for AST nodes.
|
||||
llvm::BumpPtrAllocator &Allocator;
|
||||
|
||||
/// Source manager for the comment being parsed.
|
||||
const SourceManager &SourceMgr;
|
||||
|
||||
DiagnosticsEngine &Diags;
|
||||
|
||||
const CommandTraits &Traits;
|
||||
|
||||
/// 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.
|
||||
///
|
||||
/// Contains a valid value if \c DeclInfo->IsFilled is true.
|
||||
llvm::StringMap<TParamCommandComment *> TemplateParameterDocs;
|
||||
|
||||
/// AST node for the \\brief command and its aliases.
|
||||
const BlockCommandComment *BriefCommand;
|
||||
|
||||
/// AST node for the \\returns command and its aliases.
|
||||
const BlockCommandComment *ReturnsCommand;
|
||||
|
||||
DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID) {
|
||||
return Diags.Report(Loc, DiagID);
|
||||
}
|
||||
|
||||
/// A stack of HTML tags that are currently open (not matched with closing
|
||||
/// tags).
|
||||
SmallVector<HTMLStartTagComment *, 8> HTMLOpenTags;
|
||||
|
||||
public:
|
||||
Sema(llvm::BumpPtrAllocator &Allocator, const SourceManager &SourceMgr,
|
||||
DiagnosticsEngine &Diags, const CommandTraits &Traits);
|
||||
|
||||
void setDecl(const Decl *D);
|
||||
|
||||
/// Returns a copy of array, owned by Sema's allocator.
|
||||
template<typename T>
|
||||
ArrayRef<T> copyArray(ArrayRef<T> Source) {
|
||||
size_t Size = Source.size();
|
||||
if (Size != 0) {
|
||||
T *Mem = Allocator.Allocate<T>(Size);
|
||||
std::uninitialized_copy(Source.begin(), Source.end(), Mem);
|
||||
return llvm::makeArrayRef(Mem, Size);
|
||||
} else
|
||||
return llvm::makeArrayRef(static_cast<T *>(NULL), 0);
|
||||
}
|
||||
|
||||
ParagraphComment *actOnParagraphComment(
|
||||
ArrayRef<InlineContentComment *> Content);
|
||||
|
||||
BlockCommandComment *actOnBlockCommandStart(SourceLocation LocBegin,
|
||||
SourceLocation LocEnd,
|
||||
StringRef Name);
|
||||
|
||||
void actOnBlockCommandArgs(BlockCommandComment *Command,
|
||||
ArrayRef<BlockCommandComment::Argument> Args);
|
||||
|
||||
void actOnBlockCommandFinish(BlockCommandComment *Command,
|
||||
ParagraphComment *Paragraph);
|
||||
|
||||
ParamCommandComment *actOnParamCommandStart(SourceLocation LocBegin,
|
||||
SourceLocation LocEnd,
|
||||
StringRef Name);
|
||||
|
||||
void actOnParamCommandDirectionArg(ParamCommandComment *Command,
|
||||
SourceLocation ArgLocBegin,
|
||||
SourceLocation ArgLocEnd,
|
||||
StringRef Arg);
|
||||
|
||||
void actOnParamCommandParamNameArg(ParamCommandComment *Command,
|
||||
SourceLocation ArgLocBegin,
|
||||
SourceLocation ArgLocEnd,
|
||||
StringRef Arg);
|
||||
|
||||
void actOnParamCommandFinish(ParamCommandComment *Command,
|
||||
ParagraphComment *Paragraph);
|
||||
|
||||
TParamCommandComment *actOnTParamCommandStart(SourceLocation LocBegin,
|
||||
SourceLocation LocEnd,
|
||||
StringRef Name);
|
||||
|
||||
void actOnTParamCommandParamNameArg(TParamCommandComment *Command,
|
||||
SourceLocation ArgLocBegin,
|
||||
SourceLocation ArgLocEnd,
|
||||
StringRef Arg);
|
||||
|
||||
void actOnTParamCommandFinish(TParamCommandComment *Command,
|
||||
ParagraphComment *Paragraph);
|
||||
|
||||
InlineCommandComment *actOnInlineCommand(SourceLocation CommandLocBegin,
|
||||
SourceLocation CommandLocEnd,
|
||||
StringRef CommandName);
|
||||
|
||||
InlineCommandComment *actOnInlineCommand(SourceLocation CommandLocBegin,
|
||||
SourceLocation CommandLocEnd,
|
||||
StringRef CommandName,
|
||||
SourceLocation ArgLocBegin,
|
||||
SourceLocation ArgLocEnd,
|
||||
StringRef Arg);
|
||||
|
||||
InlineContentComment *actOnUnknownCommand(SourceLocation LocBegin,
|
||||
SourceLocation LocEnd,
|
||||
StringRef Name);
|
||||
|
||||
TextComment *actOnText(SourceLocation LocBegin,
|
||||
SourceLocation LocEnd,
|
||||
StringRef Text);
|
||||
|
||||
VerbatimBlockComment *actOnVerbatimBlockStart(SourceLocation Loc,
|
||||
StringRef Name);
|
||||
|
||||
VerbatimBlockLineComment *actOnVerbatimBlockLine(SourceLocation Loc,
|
||||
StringRef Text);
|
||||
|
||||
void actOnVerbatimBlockFinish(VerbatimBlockComment *Block,
|
||||
SourceLocation CloseNameLocBegin,
|
||||
StringRef CloseName,
|
||||
ArrayRef<VerbatimBlockLineComment *> Lines);
|
||||
|
||||
VerbatimLineComment *actOnVerbatimLine(SourceLocation LocBegin,
|
||||
StringRef Name,
|
||||
SourceLocation TextBegin,
|
||||
StringRef Text);
|
||||
|
||||
HTMLStartTagComment *actOnHTMLStartTagStart(SourceLocation LocBegin,
|
||||
StringRef TagName);
|
||||
|
||||
void actOnHTMLStartTagFinish(HTMLStartTagComment *Tag,
|
||||
ArrayRef<HTMLStartTagComment::Attribute> Attrs,
|
||||
SourceLocation GreaterLoc,
|
||||
bool IsSelfClosing);
|
||||
|
||||
HTMLEndTagComment *actOnHTMLEndTag(SourceLocation LocBegin,
|
||||
SourceLocation LocEnd,
|
||||
StringRef TagName);
|
||||
|
||||
FullComment *actOnFullComment(ArrayRef<BlockContentComment *> Blocks);
|
||||
|
||||
void checkBlockCommandEmptyParagraph(BlockCommandComment *Command);
|
||||
|
||||
void checkReturnsCommand(const BlockCommandComment *Command);
|
||||
|
||||
/// Emit diagnostics about duplicate block commands that should be
|
||||
/// used only once per comment, e.g., \\brief and \\returns.
|
||||
void checkBlockCommandDuplicate(const BlockCommandComment *Command);
|
||||
|
||||
bool isFunctionDecl();
|
||||
bool isTemplateOrSpecialization();
|
||||
|
||||
ArrayRef<const ParmVarDecl *> getParamVars();
|
||||
|
||||
/// Extract all important semantic information from
|
||||
/// \c ThisDeclInfo->ThisDecl into \c ThisDeclInfo members.
|
||||
void inspectThisDecl();
|
||||
|
||||
/// Returns index of a function parameter with a given name.
|
||||
unsigned resolveParmVarReference(StringRef Name,
|
||||
ArrayRef<const ParmVarDecl *> ParamVars);
|
||||
|
||||
/// Returns index of a function parameter with the name closest to a given
|
||||
/// typo.
|
||||
unsigned correctTypoInParmVarReference(StringRef Typo,
|
||||
ArrayRef<const ParmVarDecl *> ParamVars);
|
||||
|
||||
bool resolveTParamReference(StringRef Name,
|
||||
const TemplateParameterList *TemplateParameters,
|
||||
SmallVectorImpl<unsigned> *Position);
|
||||
|
||||
StringRef correctTypoInTParamReference(
|
||||
StringRef Typo,
|
||||
const TemplateParameterList *TemplateParameters);
|
||||
|
||||
InlineCommandComment::RenderKind
|
||||
getInlineCommandRenderKind(StringRef Name) const;
|
||||
|
||||
bool isHTMLEndTagOptional(StringRef Name);
|
||||
bool isHTMLEndTagForbidden(StringRef Name);
|
||||
};
|
||||
|
||||
} // end namespace comments
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
|
||||
66
include/clang/AST/CommentVisitor.h
Normal file
66
include/clang/AST/CommentVisitor.h
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
//===--- CommentVisitor.h - Visitor for Comment subclasses ------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/AST/Comment.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
|
||||
namespace clang {
|
||||
namespace comments {
|
||||
|
||||
template <typename T> struct make_ptr { typedef T *type; };
|
||||
template <typename T> struct make_const_ptr { typedef const T *type; };
|
||||
|
||||
template<template <typename> class Ptr, typename ImplClass, typename RetTy=void>
|
||||
class CommentVisitorBase {
|
||||
public:
|
||||
#define PTR(CLASS) typename Ptr<CLASS>::type
|
||||
#define DISPATCH(NAME, CLASS) \
|
||||
return static_cast<ImplClass*>(this)->visit ## NAME(static_cast<PTR(CLASS)>(C))
|
||||
|
||||
RetTy visit(PTR(Comment) C) {
|
||||
if (!C)
|
||||
return RetTy();
|
||||
|
||||
switch (C->getCommentKind()) {
|
||||
default: llvm_unreachable("Unknown comment kind!");
|
||||
#define ABSTRACT_COMMENT(COMMENT)
|
||||
#define COMMENT(CLASS, PARENT) \
|
||||
case Comment::CLASS##Kind: DISPATCH(CLASS, CLASS);
|
||||
#include "clang/AST/CommentNodes.inc"
|
||||
#undef ABSTRACT_COMMENT
|
||||
#undef COMMENT
|
||||
}
|
||||
}
|
||||
|
||||
// If the derived class does not implement a certain Visit* method, fall back
|
||||
// on Visit* method for the superclass.
|
||||
#define ABSTRACT_COMMENT(COMMENT) COMMENT
|
||||
#define COMMENT(CLASS, PARENT) \
|
||||
RetTy visit ## CLASS(PTR(CLASS) C) { DISPATCH(PARENT, PARENT); }
|
||||
#include "clang/AST/CommentNodes.inc"
|
||||
#undef ABSTRACT_COMMENT
|
||||
#undef COMMENT
|
||||
|
||||
RetTy visitComment(PTR(Comment) C) { return RetTy(); }
|
||||
|
||||
#undef PTR
|
||||
#undef DISPATCH
|
||||
};
|
||||
|
||||
template<typename ImplClass, typename RetTy=void>
|
||||
class CommentVisitor :
|
||||
public CommentVisitorBase<make_ptr, ImplClass, RetTy> {};
|
||||
|
||||
template<typename ImplClass, typename RetTy=void>
|
||||
class ConstCommentVisitor :
|
||||
public CommentVisitorBase<make_const_ptr, ImplClass, RetTy> {};
|
||||
|
||||
} // end namespace comments
|
||||
} // end namespace clang
|
||||
|
||||
|
|
@ -99,7 +99,7 @@ public:
|
|||
};
|
||||
|
||||
/// NamedDecl - This represents a decl with a name. Many decls have names such
|
||||
/// as ObjCMethodDecl, but not @class, etc.
|
||||
/// as ObjCMethodDecl, but not \@class, etc.
|
||||
class NamedDecl : public Decl {
|
||||
virtual void anchor();
|
||||
/// Name - The name of this declaration, which is typically a normal
|
||||
|
|
@ -218,6 +218,7 @@ public:
|
|||
Visibility visibility_;
|
||||
bool explicit_;
|
||||
|
||||
void setVisibility(Visibility V, bool E) { visibility_ = V; explicit_ = E; }
|
||||
public:
|
||||
LinkageInfo() : linkage_(ExternalLinkage), visibility_(DefaultVisibility),
|
||||
explicit_(false) {}
|
||||
|
|
@ -242,8 +243,6 @@ public:
|
|||
bool visibilityExplicit() const { return explicit_; }
|
||||
|
||||
void setLinkage(Linkage L) { linkage_ = L; }
|
||||
void setVisibility(Visibility V, bool E) { visibility_ = V; explicit_ = E; }
|
||||
|
||||
void mergeLinkage(Linkage L) {
|
||||
setLinkage(minLinkage(linkage(), L));
|
||||
}
|
||||
|
|
@ -256,15 +255,15 @@ public:
|
|||
// down to one of its members. If the member has no explicit visibility,
|
||||
// the class visibility wins.
|
||||
void mergeVisibility(Visibility V, bool E = false) {
|
||||
// If one has explicit visibility and the other doesn't, keep the
|
||||
// explicit one.
|
||||
if (visibilityExplicit() && !E)
|
||||
// Never increase the visibility
|
||||
if (visibility() < V)
|
||||
return;
|
||||
if (!visibilityExplicit() && E)
|
||||
setVisibility(V, E);
|
||||
|
||||
// If both are explicit or both are implicit, keep the minimum.
|
||||
setVisibility(minVisibility(visibility(), V), visibilityExplicit() || E);
|
||||
// If we have an explicit visibility, keep it
|
||||
if (visibilityExplicit())
|
||||
return;
|
||||
|
||||
setVisibility(V, E);
|
||||
}
|
||||
// Merge the visibility V, keeping the most restrictive one.
|
||||
// This is used for cases like merging the visibility of a template
|
||||
|
|
@ -275,9 +274,16 @@ public:
|
|||
if (visibility() < V)
|
||||
return;
|
||||
|
||||
// FIXME: this
|
||||
// If this visibility is explicit, keep it.
|
||||
if (visibilityExplicit() && !E)
|
||||
return;
|
||||
|
||||
// should be replaced with this
|
||||
// Don't lose the explicit bit for nothing
|
||||
// if (visibility() == V && visibilityExplicit())
|
||||
// return;
|
||||
|
||||
setVisibility(V, E);
|
||||
}
|
||||
void mergeVisibility(LinkageInfo Other) {
|
||||
|
|
@ -295,11 +301,6 @@ public:
|
|||
mergeLinkage(Other);
|
||||
mergeVisibilityWithMin(Other);
|
||||
}
|
||||
|
||||
friend LinkageInfo merge(LinkageInfo L, LinkageInfo R) {
|
||||
L.merge(R);
|
||||
return L;
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief Determine what kind of linkage this entity has.
|
||||
|
|
@ -1151,7 +1152,7 @@ public:
|
|||
}
|
||||
|
||||
/// \brief Determine whether this variable is the exception variable in a
|
||||
/// C++ catch statememt or an Objective-C @catch statement.
|
||||
/// C++ catch statememt or an Objective-C \@catch statement.
|
||||
bool isExceptionVariable() const {
|
||||
return VarDeclBits.ExceptionVar;
|
||||
}
|
||||
|
|
@ -1182,7 +1183,7 @@ public:
|
|||
bool isARCPseudoStrong() const { return VarDeclBits.ARCPseudoStrong; }
|
||||
void setARCPseudoStrong(bool ps) { VarDeclBits.ARCPseudoStrong = ps; }
|
||||
|
||||
/// Whether this variable is (C++0x) constexpr.
|
||||
/// Whether this variable is (C++11) constexpr.
|
||||
bool isConstexpr() const { return VarDeclBits.IsConstexpr; }
|
||||
void setConstexpr(bool IC) { VarDeclBits.IsConstexpr = IC; }
|
||||
|
||||
|
|
@ -1735,9 +1736,9 @@ public:
|
|||
bool hasInheritedPrototype() const { return HasInheritedPrototype; }
|
||||
void setHasInheritedPrototype(bool P = true) { HasInheritedPrototype = P; }
|
||||
|
||||
/// Whether this is a (C++0x) constexpr function or constexpr constructor.
|
||||
/// Whether this is a (C++11) constexpr function or constexpr constructor.
|
||||
bool isConstexpr() const { return IsConstexpr; }
|
||||
void setConstexpr(bool IC) { IsConstexpr = IC; }
|
||||
void setConstexpr(bool IC);
|
||||
|
||||
/// \brief Whether this function has been deleted.
|
||||
///
|
||||
|
|
@ -2092,25 +2093,26 @@ class FieldDecl : public DeclaratorDecl {
|
|||
bool Mutable : 1;
|
||||
mutable unsigned CachedFieldIndex : 31;
|
||||
|
||||
/// \brief A pointer to either the in-class initializer for this field (if
|
||||
/// the boolean value is false), or the bit width expression for this bit
|
||||
/// field (if the boolean value is true).
|
||||
/// \brief An InClassInitStyle value, and either a bit width expression (if
|
||||
/// the InClassInitStyle value is ICIS_NoInit), or a pointer to the in-class
|
||||
/// initializer for this field (otherwise).
|
||||
///
|
||||
/// We can safely combine these two because in-class initializers are not
|
||||
/// permitted for bit-fields.
|
||||
///
|
||||
/// If the boolean is false and the initializer is null, then this field has
|
||||
/// an in-class initializer which has not yet been parsed and attached.
|
||||
llvm::PointerIntPair<Expr *, 1, bool> InitializerOrBitWidth;
|
||||
/// If the InClassInitStyle is not ICIS_NoInit and the initializer is null,
|
||||
/// then this field has an in-class initializer which has not yet been parsed
|
||||
/// and attached.
|
||||
llvm::PointerIntPair<Expr *, 2, unsigned> InitializerOrBitWidth;
|
||||
protected:
|
||||
FieldDecl(Kind DK, DeclContext *DC, SourceLocation StartLoc,
|
||||
SourceLocation IdLoc, IdentifierInfo *Id,
|
||||
QualType T, TypeSourceInfo *TInfo, Expr *BW, bool Mutable,
|
||||
bool HasInit)
|
||||
InClassInitStyle InitStyle)
|
||||
: DeclaratorDecl(DK, DC, IdLoc, Id, T, TInfo, StartLoc),
|
||||
Mutable(Mutable), CachedFieldIndex(0),
|
||||
InitializerOrBitWidth(BW, !HasInit) {
|
||||
assert(!(BW && HasInit) && "got initializer for bitfield");
|
||||
InitializerOrBitWidth(BW, InitStyle) {
|
||||
assert((!BW || InitStyle == ICIS_NoInit) && "got initializer for bitfield");
|
||||
}
|
||||
|
||||
public:
|
||||
|
|
@ -2118,7 +2120,7 @@ public:
|
|||
SourceLocation StartLoc, SourceLocation IdLoc,
|
||||
IdentifierInfo *Id, QualType T,
|
||||
TypeSourceInfo *TInfo, Expr *BW, bool Mutable,
|
||||
bool HasInit);
|
||||
InClassInitStyle InitStyle);
|
||||
|
||||
static FieldDecl *CreateDeserialized(ASTContext &C, unsigned ID);
|
||||
|
||||
|
|
@ -2129,12 +2131,10 @@ public:
|
|||
/// isMutable - Determines whether this field is mutable (C++ only).
|
||||
bool isMutable() const { return Mutable; }
|
||||
|
||||
/// \brief Set whether this field is mutable (C++ only).
|
||||
void setMutable(bool M) { Mutable = M; }
|
||||
|
||||
/// isBitfield - Determines whether this field is a bitfield.
|
||||
bool isBitField() const {
|
||||
return InitializerOrBitWidth.getInt() && InitializerOrBitWidth.getPointer();
|
||||
return getInClassInitStyle() == ICIS_NoInit &&
|
||||
InitializerOrBitWidth.getPointer();
|
||||
}
|
||||
|
||||
/// @brief Determines whether this is an unnamed bitfield.
|
||||
|
|
@ -2150,39 +2150,44 @@ public:
|
|||
return isBitField() ? InitializerOrBitWidth.getPointer() : 0;
|
||||
}
|
||||
unsigned getBitWidthValue(const ASTContext &Ctx) const;
|
||||
void setBitWidth(Expr *BW) {
|
||||
assert(!InitializerOrBitWidth.getPointer() &&
|
||||
"bit width or initializer already set");
|
||||
InitializerOrBitWidth.setPointer(BW);
|
||||
InitializerOrBitWidth.setInt(1);
|
||||
}
|
||||
/// removeBitWidth - Remove the bitfield width from this member.
|
||||
|
||||
/// setBitWidth - Set the bit-field width for this member.
|
||||
// Note: used by some clients (i.e., do not remove it).
|
||||
void setBitWidth(Expr *Width);
|
||||
/// removeBitWidth - Remove the bit-field width from this member.
|
||||
// Note: used by some clients (i.e., do not remove it).
|
||||
void removeBitWidth() {
|
||||
assert(isBitField() && "no bit width to remove");
|
||||
assert(isBitField() && "no bitfield width to remove");
|
||||
InitializerOrBitWidth.setPointer(0);
|
||||
}
|
||||
|
||||
/// hasInClassInitializer - Determine whether this member has a C++0x in-class
|
||||
/// getInClassInitStyle - Get the kind of (C++11) in-class initializer which
|
||||
/// this field has.
|
||||
InClassInitStyle getInClassInitStyle() const {
|
||||
return static_cast<InClassInitStyle>(InitializerOrBitWidth.getInt());
|
||||
}
|
||||
|
||||
/// hasInClassInitializer - Determine whether this member has a C++11 in-class
|
||||
/// initializer.
|
||||
bool hasInClassInitializer() const {
|
||||
return !InitializerOrBitWidth.getInt();
|
||||
return getInClassInitStyle() != ICIS_NoInit;
|
||||
}
|
||||
/// getInClassInitializer - Get the C++0x in-class initializer for this
|
||||
/// getInClassInitializer - Get the C++11 in-class initializer for this
|
||||
/// member, or null if one has not been set. If a valid declaration has an
|
||||
/// in-class initializer, but this returns null, then we have not parsed and
|
||||
/// attached it yet.
|
||||
Expr *getInClassInitializer() const {
|
||||
return hasInClassInitializer() ? InitializerOrBitWidth.getPointer() : 0;
|
||||
}
|
||||
/// setInClassInitializer - Set the C++0x in-class initializer for this
|
||||
/// setInClassInitializer - Set the C++11 in-class initializer for this
|
||||
/// member.
|
||||
void setInClassInitializer(Expr *Init);
|
||||
/// removeInClassInitializer - Remove the C++0x in-class initializer from this
|
||||
/// removeInClassInitializer - Remove the C++11 in-class initializer from this
|
||||
/// member.
|
||||
void removeInClassInitializer() {
|
||||
assert(!InitializerOrBitWidth.getInt() && "no initializer to remove");
|
||||
assert(hasInClassInitializer() && "no initializer to remove");
|
||||
InitializerOrBitWidth.setPointer(0);
|
||||
InitializerOrBitWidth.setInt(1);
|
||||
InitializerOrBitWidth.setInt(ICIS_NoInit);
|
||||
}
|
||||
|
||||
/// getParent - Returns the parent of this field declaration, which
|
||||
|
|
@ -2201,6 +2206,9 @@ public:
|
|||
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;
|
||||
friend class ASTDeclWriter;
|
||||
};
|
||||
|
||||
/// EnumConstantDecl - An instance of this object exists for each enum constant
|
||||
|
|
@ -2308,7 +2316,10 @@ protected:
|
|||
: NamedDecl(DK, DC, L, Id), TypeForDecl(0), LocStart(StartL) {}
|
||||
|
||||
public:
|
||||
// Low-level accessor
|
||||
// Low-level accessor. If you just want the type defined by this node,
|
||||
// check out ASTContext::getTypeDeclType or one of
|
||||
// ASTContext::getTypedefType, ASTContext::getRecordType, etc. if you
|
||||
// already know the specific kind of node this is.
|
||||
const Type *getTypeForDecl() const { return TypeForDecl; }
|
||||
void setTypeForDecl(const Type *TD) { TypeForDecl = TD; }
|
||||
|
||||
|
|
@ -2602,6 +2613,7 @@ public:
|
|||
|
||||
void setCompleteDefinition(bool V) { IsCompleteDefinition = V; }
|
||||
|
||||
// FIXME: Return StringRef;
|
||||
const char *getKindName() const {
|
||||
return TypeWithKeyword::getTagTypeKindName(getTagKind());
|
||||
}
|
||||
|
|
@ -3214,8 +3226,8 @@ public:
|
|||
/// @__experimental_modules_import std.vector;
|
||||
/// \endcode
|
||||
///
|
||||
/// Import declarations can also be implicitly generated from #include/#import
|
||||
/// directives.
|
||||
/// Import declarations can also be implicitly generated from
|
||||
/// \#include/\#import directives.
|
||||
class ImportDecl : public Decl {
|
||||
/// \brief The imported module, along with a bit that indicates whether
|
||||
/// we have source-location information for each identifier in the module
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
#define LLVM_CLANG_AST_DECLBASE_H
|
||||
|
||||
#include "clang/AST/Attr.h"
|
||||
#include "clang/AST/DeclarationName.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/Basic/Specifiers.h"
|
||||
#include "llvm/ADT/PointerUnion.h"
|
||||
|
|
@ -692,17 +693,17 @@ public:
|
|||
Decl *Starter;
|
||||
|
||||
public:
|
||||
typedef Decl* value_type;
|
||||
typedef Decl* reference;
|
||||
typedef Decl* pointer;
|
||||
typedef Decl *value_type;
|
||||
typedef const value_type &reference;
|
||||
typedef const value_type *pointer;
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
|
||||
redecl_iterator() : Current(0) { }
|
||||
explicit redecl_iterator(Decl *C) : Current(C), Starter(C) { }
|
||||
|
||||
reference operator*() const { return Current; }
|
||||
pointer operator->() const { return Current; }
|
||||
value_type operator->() const { return Current; }
|
||||
|
||||
redecl_iterator& operator++() {
|
||||
assert(Current && "Advancing while iterator has reached end");
|
||||
|
|
@ -856,8 +857,11 @@ public:
|
|||
static void printGroup(Decl** Begin, unsigned NumDecls,
|
||||
raw_ostream &Out, const PrintingPolicy &Policy,
|
||||
unsigned Indentation = 0);
|
||||
LLVM_ATTRIBUTE_USED void dump() const;
|
||||
LLVM_ATTRIBUTE_USED void dumpXML() const;
|
||||
// Debuggers don't usually respect default arguments.
|
||||
LLVM_ATTRIBUTE_USED void dump() const { dump(llvm::errs()); }
|
||||
void dump(raw_ostream &Out) const;
|
||||
// Debuggers don't usually respect default arguments.
|
||||
LLVM_ATTRIBUTE_USED void dumpXML() const { dumpXML(llvm::errs()); }
|
||||
void dumpXML(raw_ostream &OS) const;
|
||||
|
||||
private:
|
||||
|
|
@ -1141,7 +1145,7 @@ public:
|
|||
/// inline, its enclosing namespace, recursively.
|
||||
bool InEnclosingNamespaceSetOf(const DeclContext *NS) const;
|
||||
|
||||
/// \\brief Collects all of the declaration contexts that are semantically
|
||||
/// \brief Collects all of the declaration contexts that are semantically
|
||||
/// connected to this declaration context.
|
||||
///
|
||||
/// For declaration contexts that have multiple semantically connected but
|
||||
|
|
@ -1173,9 +1177,9 @@ public:
|
|||
Decl *Current;
|
||||
|
||||
public:
|
||||
typedef Decl* value_type;
|
||||
typedef Decl* reference;
|
||||
typedef Decl* pointer;
|
||||
typedef Decl *value_type;
|
||||
typedef const value_type &reference;
|
||||
typedef const value_type *pointer;
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
|
||||
|
|
@ -1183,7 +1187,8 @@ public:
|
|||
explicit decl_iterator(Decl *C) : Current(C) { }
|
||||
|
||||
reference operator*() const { return Current; }
|
||||
pointer operator->() const { return Current; }
|
||||
// This doesn't meet the iterator requirements, but it's convenient
|
||||
value_type operator->() const { return Current; }
|
||||
|
||||
decl_iterator& operator++() {
|
||||
Current = Current->getNextDeclInContext();
|
||||
|
|
@ -1207,14 +1212,14 @@ public:
|
|||
/// decls_begin/decls_end - Iterate over the declarations stored in
|
||||
/// this context.
|
||||
decl_iterator decls_begin() const;
|
||||
decl_iterator decls_end() const;
|
||||
decl_iterator decls_end() const { return decl_iterator(); }
|
||||
bool decls_empty() const;
|
||||
|
||||
/// noload_decls_begin/end - Iterate over the declarations stored in this
|
||||
/// context that are currently loaded; don't attempt to retrieve anything
|
||||
/// from an external source.
|
||||
decl_iterator noload_decls_begin() const;
|
||||
decl_iterator noload_decls_end() const;
|
||||
decl_iterator noload_decls_end() const { return decl_iterator(); }
|
||||
|
||||
/// specific_decl_iterator - Iterates over a subrange of
|
||||
/// declarations stored in a DeclContext, providing only those that
|
||||
|
|
@ -1237,9 +1242,11 @@ public:
|
|||
}
|
||||
|
||||
public:
|
||||
typedef SpecificDecl* value_type;
|
||||
typedef SpecificDecl* reference;
|
||||
typedef SpecificDecl* pointer;
|
||||
typedef SpecificDecl *value_type;
|
||||
// TODO: Add reference and pointer typedefs (with some appropriate proxy
|
||||
// type) if we ever have a need for them.
|
||||
typedef void reference;
|
||||
typedef void pointer;
|
||||
typedef std::iterator_traits<DeclContext::decl_iterator>::difference_type
|
||||
difference_type;
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
|
|
@ -1258,8 +1265,9 @@ public:
|
|||
SkipToNextDecl();
|
||||
}
|
||||
|
||||
reference operator*() const { return cast<SpecificDecl>(*Current); }
|
||||
pointer operator->() const { return cast<SpecificDecl>(*Current); }
|
||||
value_type operator*() const { return cast<SpecificDecl>(*Current); }
|
||||
// This doesn't meet the iterator requirements, but it's convenient
|
||||
value_type operator->() const { return **this; }
|
||||
|
||||
specific_decl_iterator& operator++() {
|
||||
++Current;
|
||||
|
|
@ -1311,16 +1319,18 @@ public:
|
|||
}
|
||||
|
||||
public:
|
||||
typedef SpecificDecl* value_type;
|
||||
typedef SpecificDecl* reference;
|
||||
typedef SpecificDecl* pointer;
|
||||
typedef SpecificDecl *value_type;
|
||||
// TODO: Add reference and pointer typedefs (with some appropriate proxy
|
||||
// type) if we ever have a need for them.
|
||||
typedef void reference;
|
||||
typedef void pointer;
|
||||
typedef std::iterator_traits<DeclContext::decl_iterator>::difference_type
|
||||
difference_type;
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
|
||||
filtered_decl_iterator() : Current() { }
|
||||
|
||||
/// specific_decl_iterator - Construct a new iterator over a
|
||||
/// filtered_decl_iterator - Construct a new iterator over a
|
||||
/// subset of the declarations the range [C,
|
||||
/// end-of-declarations). If A is non-NULL, it is a pointer to a
|
||||
/// member function of SpecificDecl that should return true for
|
||||
|
|
@ -1332,8 +1342,8 @@ public:
|
|||
SkipToNextDecl();
|
||||
}
|
||||
|
||||
reference operator*() const { return cast<SpecificDecl>(*Current); }
|
||||
pointer operator->() const { return cast<SpecificDecl>(*Current); }
|
||||
value_type operator*() const { return cast<SpecificDecl>(*Current); }
|
||||
value_type operator->() const { return cast<SpecificDecl>(*Current); }
|
||||
|
||||
filtered_decl_iterator& operator++() {
|
||||
++Current;
|
||||
|
|
@ -1410,7 +1420,9 @@ public:
|
|||
/// and enumerator names preceding any tag name. Note that this
|
||||
/// routine will not look into parent contexts.
|
||||
lookup_result lookup(DeclarationName Name);
|
||||
lookup_const_result lookup(DeclarationName Name) const;
|
||||
lookup_const_result lookup(DeclarationName Name) const {
|
||||
return const_cast<DeclContext*>(this)->lookup(Name);
|
||||
}
|
||||
|
||||
/// \brief A simplistic name lookup mechanism that performs name lookup
|
||||
/// into this declaration context without consulting the external source.
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ class CXXFinalOverriderMap;
|
|||
class CXXIndirectPrimaryBaseSet;
|
||||
class FriendDecl;
|
||||
class LambdaExpr;
|
||||
class UsingDecl;
|
||||
|
||||
/// \brief Represents any kind of function declaration, whether it is a
|
||||
/// concrete function or a function template.
|
||||
|
|
@ -98,7 +99,7 @@ namespace llvm {
|
|||
|
||||
namespace clang {
|
||||
|
||||
/// AccessSpecDecl - An access specifier followed by colon ':'.
|
||||
/// @brief Represents an access specifier followed by colon ':'.
|
||||
///
|
||||
/// An objects of this class represents sugar for the syntactic occurrence
|
||||
/// of an access specifier followed by a colon in the list of member
|
||||
|
|
@ -110,7 +111,7 @@ namespace clang {
|
|||
/// "access declarations" (C++98 11.3 [class.access.dcl]).
|
||||
class AccessSpecDecl : public Decl {
|
||||
virtual void anchor();
|
||||
/// ColonLoc - The location of the ':'.
|
||||
/// \brief The location of the ':'.
|
||||
SourceLocation ColonLoc;
|
||||
|
||||
AccessSpecDecl(AccessSpecifier AS, DeclContext *DC,
|
||||
|
|
@ -121,14 +122,14 @@ class AccessSpecDecl : public Decl {
|
|||
AccessSpecDecl(EmptyShell Empty)
|
||||
: Decl(AccessSpec, Empty) { }
|
||||
public:
|
||||
/// getAccessSpecifierLoc - The location of the access specifier.
|
||||
/// \brief The location of the access specifier.
|
||||
SourceLocation getAccessSpecifierLoc() const { return getLocation(); }
|
||||
/// setAccessSpecifierLoc - Sets the location of the access specifier.
|
||||
/// \brief Sets the location of the access specifier.
|
||||
void setAccessSpecifierLoc(SourceLocation ASLoc) { setLocation(ASLoc); }
|
||||
|
||||
/// getColonLoc - The location of the colon following the access specifier.
|
||||
/// \brief The location of the colon following the access specifier.
|
||||
SourceLocation getColonLoc() const { return ColonLoc; }
|
||||
/// setColonLoc - Sets the location of the colon.
|
||||
/// \brief Sets the location of the colon.
|
||||
void setColonLoc(SourceLocation CLoc) { ColonLoc = CLoc; }
|
||||
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
|
|
@ -149,7 +150,7 @@ public:
|
|||
};
|
||||
|
||||
|
||||
/// CXXBaseSpecifier - A base class of a C++ class.
|
||||
/// \brief Represents a base class of a C++ class.
|
||||
///
|
||||
/// Each CXXBaseSpecifier represents a single, direct base class (or
|
||||
/// struct) of a C++ class (or struct). It specifies the type of that
|
||||
|
|
@ -175,7 +176,7 @@ class CXXBaseSpecifier {
|
|||
/// expansion.
|
||||
SourceLocation EllipsisLoc;
|
||||
|
||||
/// Virtual - Whether this is a virtual base class or not.
|
||||
/// \brief Whether this is a virtual base class or not.
|
||||
bool Virtual : 1;
|
||||
|
||||
/// BaseOfClass - Whether this is the base of a class (true) or of a
|
||||
|
|
@ -357,6 +358,9 @@ class CXXRecordDecl : public RecordDecl {
|
|||
/// \brief True if there no non-field members declared by the user.
|
||||
bool HasOnlyCMembers : 1;
|
||||
|
||||
/// \brief True if any field has an in-class initializer.
|
||||
bool HasInClassInitializer : 1;
|
||||
|
||||
/// HasTrivialDefaultConstructor - True when, if this class has a default
|
||||
/// constructor, this default constructor is trivial.
|
||||
///
|
||||
|
|
@ -382,26 +386,10 @@ class CXXRecordDecl : public RecordDecl {
|
|||
/// constructor for this class would be constexpr.
|
||||
bool DefaultedDefaultConstructorIsConstexpr : 1;
|
||||
|
||||
/// DefaultedCopyConstructorIsConstexpr - True if a defaulted copy
|
||||
/// constructor for this class would be constexpr.
|
||||
bool DefaultedCopyConstructorIsConstexpr : 1;
|
||||
|
||||
/// DefaultedMoveConstructorIsConstexpr - True if a defaulted move
|
||||
/// constructor for this class would be constexpr.
|
||||
bool DefaultedMoveConstructorIsConstexpr : 1;
|
||||
|
||||
/// HasConstexprDefaultConstructor - True if this class has a constexpr
|
||||
/// default constructor (either user-declared or implicitly declared).
|
||||
bool HasConstexprDefaultConstructor : 1;
|
||||
|
||||
/// HasConstexprCopyConstructor - True if this class has a constexpr copy
|
||||
/// constructor (either user-declared or implicitly declared).
|
||||
bool HasConstexprCopyConstructor : 1;
|
||||
|
||||
/// HasConstexprMoveConstructor - True if this class has a constexpr move
|
||||
/// constructor (either user-declared or implicitly declared).
|
||||
bool HasConstexprMoveConstructor : 1;
|
||||
|
||||
/// HasTrivialCopyConstructor - True when this class has a trivial copy
|
||||
/// constructor.
|
||||
///
|
||||
|
|
@ -554,13 +542,21 @@ class CXXRecordDecl : public RecordDecl {
|
|||
|
||||
/// \brief Retrieve the set of direct base classes.
|
||||
CXXBaseSpecifier *getBases() const {
|
||||
return Bases.get(Definition->getASTContext().getExternalSource());
|
||||
if (!Bases.isOffset())
|
||||
return Bases.get(0);
|
||||
return getBasesSlowCase();
|
||||
}
|
||||
|
||||
/// \brief Retrieve the set of virtual base classes.
|
||||
CXXBaseSpecifier *getVBases() const {
|
||||
return VBases.get(Definition->getASTContext().getExternalSource());
|
||||
if (!VBases.isOffset())
|
||||
return VBases.get(0);
|
||||
return getVBasesSlowCase();
|
||||
}
|
||||
|
||||
private:
|
||||
CXXBaseSpecifier *getBasesSlowCase() const;
|
||||
CXXBaseSpecifier *getVBasesSlowCase() const;
|
||||
} *DefinitionData;
|
||||
|
||||
/// \brief Describes a C++ closure type (generated by a lambda expression).
|
||||
|
|
@ -647,6 +643,9 @@ class CXXRecordDecl : public RecordDecl {
|
|||
void markedVirtualFunctionPure();
|
||||
friend void FunctionDecl::setPure(bool);
|
||||
|
||||
void markedConstructorConstexpr(CXXConstructorDecl *CD);
|
||||
friend void FunctionDecl::setConstexpr(bool);
|
||||
|
||||
friend class ASTNodeImporter;
|
||||
|
||||
protected:
|
||||
|
|
@ -1040,6 +1039,10 @@ public:
|
|||
/// no base classes, and no virtual functions (C++ [dcl.init.aggr]p1).
|
||||
bool isAggregate() const { return data().Aggregate; }
|
||||
|
||||
/// hasInClassInitializer - Whether this class has any in-class initializers
|
||||
/// for non-static data members.
|
||||
bool hasInClassInitializer() const { return data().HasInClassInitializer; }
|
||||
|
||||
/// isPOD - Whether this class is a POD-type (C++ [class]p4), which is a class
|
||||
/// that is an aggregate that has no non-static non-POD data members, no
|
||||
/// reference data members, no user-defined copy assignment operator and no
|
||||
|
|
@ -1091,19 +1094,8 @@ public:
|
|||
/// defaultedDefaultConstructorIsConstexpr - Whether a defaulted default
|
||||
/// constructor for this class would be constexpr.
|
||||
bool defaultedDefaultConstructorIsConstexpr() const {
|
||||
return data().DefaultedDefaultConstructorIsConstexpr;
|
||||
}
|
||||
|
||||
/// defaultedCopyConstructorIsConstexpr - Whether a defaulted copy
|
||||
/// constructor for this class would be constexpr.
|
||||
bool defaultedCopyConstructorIsConstexpr() const {
|
||||
return data().DefaultedCopyConstructorIsConstexpr;
|
||||
}
|
||||
|
||||
/// defaultedMoveConstructorIsConstexpr - Whether a defaulted move
|
||||
/// constructor for this class would be constexpr.
|
||||
bool defaultedMoveConstructorIsConstexpr() const {
|
||||
return data().DefaultedMoveConstructorIsConstexpr;
|
||||
return data().DefaultedDefaultConstructorIsConstexpr &&
|
||||
(!isUnion() || hasInClassInitializer());
|
||||
}
|
||||
|
||||
/// hasConstexprDefaultConstructor - Whether this class has a constexpr
|
||||
|
|
@ -1111,23 +1103,7 @@ public:
|
|||
bool hasConstexprDefaultConstructor() const {
|
||||
return data().HasConstexprDefaultConstructor ||
|
||||
(!data().UserDeclaredConstructor &&
|
||||
data().DefaultedDefaultConstructorIsConstexpr && isLiteral());
|
||||
}
|
||||
|
||||
/// hasConstexprCopyConstructor - Whether this class has a constexpr copy
|
||||
/// constructor.
|
||||
bool hasConstexprCopyConstructor() const {
|
||||
return data().HasConstexprCopyConstructor ||
|
||||
(!data().DeclaredCopyConstructor &&
|
||||
data().DefaultedCopyConstructorIsConstexpr && isLiteral());
|
||||
}
|
||||
|
||||
/// hasConstexprMoveConstructor - Whether this class has a constexpr move
|
||||
/// constructor.
|
||||
bool hasConstexprMoveConstructor() const {
|
||||
return data().HasConstexprMoveConstructor ||
|
||||
(needsImplicitMoveConstructor() &&
|
||||
data().DefaultedMoveConstructorIsConstexpr && isLiteral());
|
||||
defaultedDefaultConstructorIsConstexpr());
|
||||
}
|
||||
|
||||
// hasTrivialCopyConstructor - Whether this class has a trivial copy
|
||||
|
|
@ -1212,12 +1188,12 @@ public:
|
|||
/// This routine will return non-NULL for (non-templated) member
|
||||
/// classes of class templates. For example, given:
|
||||
///
|
||||
/// \code
|
||||
/// @code
|
||||
/// template<typename T>
|
||||
/// struct X {
|
||||
/// struct A { };
|
||||
/// };
|
||||
/// \endcode
|
||||
/// @endcode
|
||||
///
|
||||
/// The declaration for X<int>::A is a (non-templated) CXXRecordDecl
|
||||
/// whose parent is the class template specialization X<int>. For
|
||||
|
|
@ -1319,7 +1295,7 @@ public:
|
|||
///
|
||||
/// \returns true if this class is virtually derived from Base,
|
||||
/// false otherwise.
|
||||
bool isVirtuallyDerivedFrom(CXXRecordDecl *Base) const;
|
||||
bool isVirtuallyDerivedFrom(const CXXRecordDecl *Base) const;
|
||||
|
||||
/// \brief Determine whether this class is provably not derived from
|
||||
/// the type \p Base.
|
||||
|
|
@ -1573,6 +1549,9 @@ public:
|
|||
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 isVirtual() const {
|
||||
CXXMethodDecl *CD =
|
||||
cast<CXXMethodDecl>(const_cast<CXXMethodDecl*>(this)->getCanonicalDecl());
|
||||
|
|
@ -1602,8 +1581,8 @@ public:
|
|||
return cast<CXXMethodDecl>(FunctionDecl::getCanonicalDecl());
|
||||
}
|
||||
|
||||
/// isUserProvided - True if it is either an implicit constructor or
|
||||
/// if it was defaulted or deleted on first declaration.
|
||||
/// isUserProvided - True if this method is user-declared and was not
|
||||
/// deleted or defaulted on its first declaration.
|
||||
bool isUserProvided() const {
|
||||
return !(isDeleted() || getCanonicalDecl()->isDefaulted());
|
||||
}
|
||||
|
|
@ -1642,13 +1621,13 @@ public:
|
|||
///
|
||||
/// In the following example, \c f() has an lvalue ref-qualifier, \c g()
|
||||
/// has an rvalue ref-qualifier, and \c h() has no ref-qualifier.
|
||||
/// \code
|
||||
/// @code
|
||||
/// struct X {
|
||||
/// void f() &;
|
||||
/// void g() &&;
|
||||
/// void h();
|
||||
/// };
|
||||
/// \endcode
|
||||
/// @endcode
|
||||
RefQualifierKind getRefQualifier() const {
|
||||
return getType()->getAs<FunctionProtoType>()->getRefQualifier();
|
||||
}
|
||||
|
|
@ -1663,7 +1642,20 @@ public:
|
|||
/// supplied by IR generation to either forward to the function call operator
|
||||
/// or clone the function call operator.
|
||||
bool isLambdaStaticInvoker() const;
|
||||
|
||||
|
||||
/// \brief Find the method in RD that corresponds to this one.
|
||||
///
|
||||
/// Find if RD or one of the classes it inherits from override this method.
|
||||
/// If so, return it. RD is assumed to be a base class of the class defining
|
||||
/// this method (or be the class itself).
|
||||
CXXMethodDecl *
|
||||
getCorrespondingMethodInClass(const CXXRecordDecl *RD);
|
||||
|
||||
const CXXMethodDecl *
|
||||
getCorrespondingMethodInClass(const CXXRecordDecl *RD) const {
|
||||
return const_cast<CXXMethodDecl*>(this)->getCorrespondingMethodInClass(RD);
|
||||
}
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const CXXMethodDecl *D) { return true; }
|
||||
|
|
@ -2468,7 +2460,9 @@ public:
|
|||
friend class ASTDeclReader;
|
||||
};
|
||||
|
||||
/// NamespaceAliasDecl - Represents a C++ namespace alias. For example:
|
||||
/// \brief Represents a C++ namespace alias.
|
||||
///
|
||||
/// For example:
|
||||
///
|
||||
/// @code
|
||||
/// namespace Foo = Bar;
|
||||
|
|
@ -2555,17 +2549,19 @@ public:
|
|||
static bool classofKind(Kind K) { return K == NamespaceAlias; }
|
||||
};
|
||||
|
||||
/// UsingShadowDecl - Represents a shadow declaration introduced into
|
||||
/// a scope by a (resolved) using declaration. For example,
|
||||
/// \brief Represents a shadow declaration introduced into a scope by a
|
||||
/// (resolved) using declaration.
|
||||
///
|
||||
/// For example,
|
||||
/// @code
|
||||
/// namespace A {
|
||||
/// void foo();
|
||||
/// }
|
||||
/// namespace B {
|
||||
/// using A::foo(); // <- a UsingDecl
|
||||
/// // Also creates a UsingShadowDecl for A::foo in B
|
||||
/// using A::foo; // <- a UsingDecl
|
||||
/// // Also creates a UsingShadowDecl for A::foo() in B
|
||||
/// }
|
||||
///
|
||||
/// @endcode
|
||||
class UsingShadowDecl : public NamedDecl {
|
||||
virtual void anchor();
|
||||
|
||||
|
|
@ -2627,8 +2623,12 @@ public:
|
|||
friend class ASTDeclWriter;
|
||||
};
|
||||
|
||||
/// UsingDecl - Represents a C++ using-declaration. For example:
|
||||
/// \brief Represents a C++ using-declaration.
|
||||
///
|
||||
/// For example:
|
||||
/// @code
|
||||
/// using someNameSpace::someIdentifier;
|
||||
/// @endcode
|
||||
class UsingDecl : public NamedDecl {
|
||||
virtual void anchor();
|
||||
|
||||
|
|
@ -2643,8 +2643,10 @@ class UsingDecl : public NamedDecl {
|
|||
DeclarationNameLoc DNLoc;
|
||||
|
||||
/// \brief The first shadow declaration of the shadow decl chain associated
|
||||
/// with this using declaration. The bool member of the pair store whether
|
||||
/// this decl has the 'typename' keyword.
|
||||
/// with this using declaration.
|
||||
///
|
||||
/// The bool member of the pair store whether this decl has the \c typename
|
||||
/// keyword.
|
||||
llvm::PointerIntPair<UsingShadowDecl *, 1, bool> FirstUsingShadow;
|
||||
|
||||
UsingDecl(DeclContext *DC, SourceLocation UL,
|
||||
|
|
@ -2753,14 +2755,17 @@ public:
|
|||
friend class ASTDeclWriter;
|
||||
};
|
||||
|
||||
/// UnresolvedUsingValueDecl - Represents a dependent using
|
||||
/// declaration which was not marked with 'typename'. Unlike
|
||||
/// non-dependent using declarations, these *only* bring through
|
||||
/// \brief Represents a dependent using declaration which was not marked with
|
||||
/// \c typename.
|
||||
///
|
||||
/// Unlike non-dependent using declarations, these *only* bring through
|
||||
/// non-types; otherwise they would break two-phase lookup.
|
||||
///
|
||||
/// template <class T> class A : public Base<T> {
|
||||
/// @code
|
||||
/// template \<class T> class A : public Base<T> {
|
||||
/// using Base<T>::foo;
|
||||
/// };
|
||||
/// @endcode
|
||||
class UnresolvedUsingValueDecl : public ValueDecl {
|
||||
virtual void anchor();
|
||||
|
||||
|
|
@ -2824,14 +2829,16 @@ public:
|
|||
friend class ASTDeclWriter;
|
||||
};
|
||||
|
||||
/// UnresolvedUsingTypenameDecl - Represents a dependent using
|
||||
/// declaration which was marked with 'typename'.
|
||||
/// @brief Represents a dependent using declaration which was marked with
|
||||
/// \c typename.
|
||||
///
|
||||
/// template <class T> class A : public Base<T> {
|
||||
/// @code
|
||||
/// template \<class T> class A : public Base<T> {
|
||||
/// using typename Base<T>::foo;
|
||||
/// };
|
||||
/// @endcode
|
||||
///
|
||||
/// The type associated with a unresolved using typename decl is
|
||||
/// The type associated with an unresolved using typename decl is
|
||||
/// currently always a typename type.
|
||||
class UnresolvedUsingTypenameDecl : public TypeDecl {
|
||||
virtual void anchor();
|
||||
|
|
@ -2885,34 +2892,36 @@ public:
|
|||
static bool classofKind(Kind K) { return K == UnresolvedUsingTypename; }
|
||||
};
|
||||
|
||||
/// StaticAssertDecl - Represents a C++0x static_assert declaration.
|
||||
/// \brief Represents a C++11 static_assert declaration.
|
||||
class StaticAssertDecl : public Decl {
|
||||
virtual void anchor();
|
||||
Expr *AssertExpr;
|
||||
llvm::PointerIntPair<Expr *, 1, bool> AssertExprAndFailed;
|
||||
StringLiteral *Message;
|
||||
SourceLocation RParenLoc;
|
||||
|
||||
StaticAssertDecl(DeclContext *DC, SourceLocation StaticAssertLoc,
|
||||
Expr *assertexpr, StringLiteral *message,
|
||||
SourceLocation RParenLoc)
|
||||
: Decl(StaticAssert, DC, StaticAssertLoc), AssertExpr(assertexpr),
|
||||
Message(message), RParenLoc(RParenLoc) { }
|
||||
Expr *AssertExpr, StringLiteral *Message,
|
||||
SourceLocation RParenLoc, bool Failed)
|
||||
: Decl(StaticAssert, DC, StaticAssertLoc),
|
||||
AssertExprAndFailed(AssertExpr, Failed), Message(Message),
|
||||
RParenLoc(RParenLoc) { }
|
||||
|
||||
public:
|
||||
static StaticAssertDecl *Create(ASTContext &C, DeclContext *DC,
|
||||
SourceLocation StaticAssertLoc,
|
||||
Expr *AssertExpr, StringLiteral *Message,
|
||||
SourceLocation RParenLoc);
|
||||
SourceLocation RParenLoc, bool Failed);
|
||||
static StaticAssertDecl *CreateDeserialized(ASTContext &C, unsigned ID);
|
||||
|
||||
Expr *getAssertExpr() { return AssertExpr; }
|
||||
const Expr *getAssertExpr() const { return AssertExpr; }
|
||||
Expr *getAssertExpr() { return AssertExprAndFailed.getPointer(); }
|
||||
const Expr *getAssertExpr() const { return AssertExprAndFailed.getPointer(); }
|
||||
|
||||
StringLiteral *getMessage() { return Message; }
|
||||
const StringLiteral *getMessage() const { return Message; }
|
||||
|
||||
bool isFailed() const { return AssertExprAndFailed.getInt(); }
|
||||
|
||||
SourceLocation getRParenLoc() const { return RParenLoc; }
|
||||
void setRParenLoc(SourceLocation L) { RParenLoc = L; }
|
||||
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
return SourceRange(getLocation(), getRParenLoc());
|
||||
|
|
@ -2925,7 +2934,7 @@ public:
|
|||
friend class ASTDeclReader;
|
||||
};
|
||||
|
||||
/// Insertion operator for diagnostics. This allows sending AccessSpecifier's
|
||||
/// Insertion operator for diagnostics. This allows sending an AccessSpecifier
|
||||
/// into a diagnostic with <<.
|
||||
const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
|
||||
AccessSpecifier AS);
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@
|
|||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/DeclarationName.h"
|
||||
#include "clang/AST/DeclCXX.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/PointerUnion.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include <algorithm>
|
||||
|
||||
|
|
@ -196,7 +196,7 @@ public:
|
|||
};
|
||||
|
||||
class StoredDeclsMap
|
||||
: public llvm::DenseMap<DeclarationName, StoredDeclsList> {
|
||||
: public llvm::SmallDenseMap<DeclarationName, StoredDeclsList, 4> {
|
||||
|
||||
public:
|
||||
static void DestroyAll(StoredDeclsMap *Map, bool Dependent);
|
||||
|
|
|
|||
|
|
@ -71,10 +71,12 @@ private:
|
|||
: Decl(Decl::Friend, Empty), NextFriend() { }
|
||||
|
||||
FriendDecl *getNextFriend() {
|
||||
return cast_or_null<FriendDecl>(
|
||||
NextFriend.get(getASTContext().getExternalSource()));
|
||||
if (!NextFriend.isOffset())
|
||||
return cast_or_null<FriendDecl>(NextFriend.get(0));
|
||||
return getNextFriendSlowCase();
|
||||
}
|
||||
|
||||
FriendDecl *getNextFriendSlowCase();
|
||||
|
||||
public:
|
||||
static FriendDecl *Create(ASTContext &C, DeclContext *DC,
|
||||
SourceLocation L, FriendUnion Friend_,
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@ private:
|
|||
mutable unsigned HasRedeclaration : 1;
|
||||
|
||||
// NOTE: VC++ treats enums as signed, avoid using ImplementationControl enum
|
||||
/// @required/@optional
|
||||
/// \@required/\@optional
|
||||
unsigned DeclImplementation : 2;
|
||||
|
||||
// NOTE: VC++ treats enums as signed, avoid using the ObjCDeclQualifier enum
|
||||
|
|
@ -150,6 +150,15 @@ private:
|
|||
/// "standard" position, a enum SelectorLocationsKind.
|
||||
unsigned SelLocsKind : 2;
|
||||
|
||||
/// \brief Whether this method overrides any other in the class hierarchy.
|
||||
///
|
||||
/// A method is said to override any method in the class's
|
||||
/// base classes, 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.
|
||||
unsigned IsOverriding : 1;
|
||||
|
||||
// Result type of this method.
|
||||
QualType MethodDeclType;
|
||||
|
||||
|
|
@ -162,7 +171,7 @@ private:
|
|||
unsigned NumParams;
|
||||
|
||||
/// List of attributes for this method declaration.
|
||||
SourceLocation EndLoc; // the location of the ';' or '}'.
|
||||
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.
|
||||
|
|
@ -230,10 +239,10 @@ private:
|
|||
IsDefined(isDefined), IsRedeclaration(0), HasRedeclaration(0),
|
||||
DeclImplementation(impControl), objcDeclQualifier(OBJC_TQ_None),
|
||||
RelatedResultType(HasRelatedResultType),
|
||||
SelLocsKind(SelLoc_StandardNoSpace),
|
||||
SelLocsKind(SelLoc_StandardNoSpace), IsOverriding(0),
|
||||
MethodDeclType(T), ResultTInfo(ResultTInfo),
|
||||
ParamsAndSelLocs(0), NumParams(0),
|
||||
EndLoc(endLoc), Body(0), SelfDecl(0), CmdDecl(0) {
|
||||
DeclEndLoc(endLoc), Body(0), SelfDecl(0), CmdDecl(0) {
|
||||
setImplicit(isImplicitlyDeclared);
|
||||
}
|
||||
|
||||
|
|
@ -281,12 +290,16 @@ public:
|
|||
bool isRedeclaration() const { return IsRedeclaration; }
|
||||
void setAsRedeclaration(const ObjCMethodDecl *PrevMethod);
|
||||
|
||||
/// \brief Returns the location where the declarator ends. It will be
|
||||
/// the location of ';' for a method declaration and the location of '{'
|
||||
/// for a method definition.
|
||||
SourceLocation getDeclaratorEndLoc() const { return DeclEndLoc; }
|
||||
|
||||
// Location information, modeled after the Stmt API.
|
||||
SourceLocation getLocStart() const LLVM_READONLY { return getLocation(); }
|
||||
SourceLocation getLocEnd() const LLVM_READONLY { return EndLoc; }
|
||||
void setEndLoc(SourceLocation Loc) { EndLoc = Loc; }
|
||||
SourceLocation getLocEnd() const LLVM_READONLY;
|
||||
virtual SourceRange getSourceRange() const LLVM_READONLY {
|
||||
return SourceRange(getLocation(), EndLoc);
|
||||
return SourceRange(getLocation(), getLocEnd());
|
||||
}
|
||||
|
||||
SourceLocation getSelectorStartLoc() const {
|
||||
|
|
@ -301,7 +314,7 @@ public:
|
|||
getSelLocsKind() == SelLoc_StandardWithSpace,
|
||||
llvm::makeArrayRef(const_cast<ParmVarDecl**>(getParams()),
|
||||
NumParams),
|
||||
EndLoc);
|
||||
DeclEndLoc);
|
||||
return getStoredSelLocs()[Index];
|
||||
}
|
||||
|
||||
|
|
@ -396,7 +409,17 @@ public:
|
|||
bool isDefined() const { return IsDefined; }
|
||||
void setDefined(bool isDefined) { IsDefined = isDefined; }
|
||||
|
||||
// Related to protocols declared in @protocol
|
||||
/// \brief Whether this method overrides any other in the class hierarchy.
|
||||
///
|
||||
/// A method is said to override any method in the class's
|
||||
/// base classes, 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.
|
||||
bool isOverriding() const { return IsOverriding; }
|
||||
void setOverriding(bool isOverriding) { IsOverriding = isOverriding; }
|
||||
|
||||
// Related to protocols declared in \@protocol
|
||||
void setDeclImplementation(ImplementationControl ic) {
|
||||
DeclImplementation = ic;
|
||||
}
|
||||
|
|
@ -528,24 +551,28 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
/// ObjCInterfaceDecl - Represents an ObjC class declaration. For example:
|
||||
/// \brief Represents an ObjC class declaration.
|
||||
///
|
||||
/// For example:
|
||||
///
|
||||
/// \code
|
||||
/// // MostPrimitive declares no super class (not particularly useful).
|
||||
/// @interface MostPrimitive
|
||||
/// \@interface MostPrimitive
|
||||
/// // no instance variables or methods.
|
||||
/// @end
|
||||
/// \@end
|
||||
///
|
||||
/// // NSResponder inherits from NSObject & implements NSCoding (a protocol).
|
||||
/// @interface NSResponder : NSObject <NSCoding>
|
||||
/// \@interface NSResponder : NSObject \<NSCoding>
|
||||
/// { // instance variables are represented by ObjCIvarDecl.
|
||||
/// id nextResponder; // nextResponder instance variable.
|
||||
/// }
|
||||
/// - (NSResponder *)nextResponder; // return a pointer to NSResponder.
|
||||
/// - (void)mouseMoved:(NSEvent *)theEvent; // return void, takes a pointer
|
||||
/// @end // to an NSEvent.
|
||||
/// \@end // to an NSEvent.
|
||||
/// \endcode
|
||||
///
|
||||
/// Unlike C/C++, forward class declarations are accomplished with @class.
|
||||
/// Unlike C/C++, @class allows for a list of classes to be forward declared.
|
||||
/// Unlike C/C++, forward class declarations are accomplished with \@class.
|
||||
/// Unlike C/C++, \@class allows for a list of classes to be forward declared.
|
||||
/// Unlike C++, ObjC is a single-rooted class model. In Cocoa, classes
|
||||
/// typically inherit from NSObject (an exception is NSProxy).
|
||||
///
|
||||
|
|
@ -566,10 +593,10 @@ class ObjCInterfaceDecl : public ObjCContainerDecl
|
|||
/// Class's super class.
|
||||
ObjCInterfaceDecl *SuperClass;
|
||||
|
||||
/// Protocols referenced in the @interface declaration
|
||||
/// Protocols referenced in the \@interface declaration
|
||||
ObjCProtocolList ReferencedProtocols;
|
||||
|
||||
/// Protocols reference in both the @interface and class extensions.
|
||||
/// Protocols reference in both the \@interface and class extensions.
|
||||
ObjCList<ObjCProtocolDecl> AllReferencedProtocols;
|
||||
|
||||
/// \brief List of categories and class extensions defined for this class.
|
||||
|
|
@ -799,21 +826,21 @@ public:
|
|||
bool hasDefinition() const { return Data; }
|
||||
|
||||
/// \brief Retrieve the definition of this class, or NULL if this class
|
||||
/// has been forward-declared (with @class) but not yet defined (with
|
||||
/// @interface).
|
||||
/// has been forward-declared (with \@class) but not yet defined (with
|
||||
/// \@interface).
|
||||
ObjCInterfaceDecl *getDefinition() {
|
||||
return hasDefinition()? Data->Definition : 0;
|
||||
}
|
||||
|
||||
/// \brief Retrieve the definition of this class, or NULL if this class
|
||||
/// has been forward-declared (with @class) but not yet defined (with
|
||||
/// @interface).
|
||||
/// has been forward-declared (with \@class) but not yet defined (with
|
||||
/// \@interface).
|
||||
const ObjCInterfaceDecl *getDefinition() const {
|
||||
return hasDefinition()? Data->Definition : 0;
|
||||
}
|
||||
|
||||
/// \brief Starts the definition of this Objective-C class, taking it from
|
||||
/// a forward declaration (@class) to a definition (@interface).
|
||||
/// a forward declaration (\@class) to a definition (\@interface).
|
||||
void startDefinition();
|
||||
|
||||
ObjCInterfaceDecl *getSuperClass() const {
|
||||
|
|
@ -879,8 +906,8 @@ public:
|
|||
}
|
||||
|
||||
/// isObjCRequiresPropertyDefs - Checks that a class or one of its super
|
||||
/// classes must not be auto-synthesized. Returns class decl. if it must not be;
|
||||
/// 0, otherwise.
|
||||
/// classes must not be auto-synthesized. Returns class decl. if it must not
|
||||
/// be; 0, otherwise.
|
||||
const ObjCInterfaceDecl *isObjCRequiresPropertyDefs() const {
|
||||
const ObjCInterfaceDecl *Class = this;
|
||||
while (Class) {
|
||||
|
|
@ -912,8 +939,13 @@ public:
|
|||
}
|
||||
ObjCInterfaceDecl *lookupInheritedClass(const IdentifierInfo *ICName);
|
||||
|
||||
// Lookup a method in the classes implementation hierarchy.
|
||||
ObjCMethodDecl *lookupPrivateMethod(const Selector &Sel, bool Instance=true);
|
||||
/// \brief Lookup a method in the classes implementation hierarchy.
|
||||
ObjCMethodDecl *lookupPrivateMethod(const Selector &Sel,
|
||||
bool Instance=true) const;
|
||||
|
||||
ObjCMethodDecl *lookupPrivateClassMethod(const Selector &Sel) {
|
||||
return lookupPrivateMethod(Sel, false);
|
||||
}
|
||||
|
||||
SourceLocation getEndOfDefinitionLoc() const {
|
||||
if (!hasDefinition())
|
||||
|
|
@ -928,8 +960,8 @@ public:
|
|||
SourceLocation getSuperClassLoc() const { return data().SuperClassLoc; }
|
||||
|
||||
/// isImplicitInterfaceDecl - check that this is an implicitly declared
|
||||
/// ObjCInterfaceDecl node. This is for legacy objective-c @implementation
|
||||
/// declaration without an @interface declaration.
|
||||
/// ObjCInterfaceDecl node. This is for legacy objective-c \@implementation
|
||||
/// declaration without an \@interface declaration.
|
||||
bool isImplicitInterfaceDecl() const {
|
||||
return hasDefinition() ? Data->Definition->isImplicit() : isImplicit();
|
||||
}
|
||||
|
|
@ -972,14 +1004,14 @@ public:
|
|||
/// instance variables are identical to C. The only exception is Objective-C
|
||||
/// supports C++ style access control. For example:
|
||||
///
|
||||
/// @interface IvarExample : NSObject
|
||||
/// \@interface IvarExample : NSObject
|
||||
/// {
|
||||
/// id defaultToProtected;
|
||||
/// @public:
|
||||
/// \@public:
|
||||
/// id canBePublic; // same as C++.
|
||||
/// @protected:
|
||||
/// \@protected:
|
||||
/// id canBeProtected; // same as C++.
|
||||
/// @package:
|
||||
/// \@package:
|
||||
/// id canBePackage; // framework visibility (not available in C++).
|
||||
/// }
|
||||
///
|
||||
|
|
@ -997,7 +1029,7 @@ private:
|
|||
QualType T, TypeSourceInfo *TInfo, AccessControl ac, Expr *BW,
|
||||
bool synthesized)
|
||||
: FieldDecl(ObjCIvar, DC, StartLoc, IdLoc, Id, T, TInfo, BW,
|
||||
/*Mutable=*/false, /*HasInit=*/false),
|
||||
/*Mutable=*/false, /*HasInit=*/ICIS_NoInit),
|
||||
NextIvar(0), DeclAccess(ac), Synthesized(synthesized) {}
|
||||
|
||||
public:
|
||||
|
|
@ -1046,8 +1078,7 @@ private:
|
|||
};
|
||||
|
||||
|
||||
/// ObjCAtDefsFieldDecl - Represents a field declaration created by an
|
||||
/// @defs(...).
|
||||
/// \brief Represents a field declaration created by an \@defs(...).
|
||||
class ObjCAtDefsFieldDecl : public FieldDecl {
|
||||
virtual void anchor();
|
||||
ObjCAtDefsFieldDecl(DeclContext *DC, SourceLocation StartLoc,
|
||||
|
|
@ -1055,7 +1086,7 @@ class ObjCAtDefsFieldDecl : public FieldDecl {
|
|||
QualType T, Expr *BW)
|
||||
: FieldDecl(ObjCAtDefsField, DC, StartLoc, IdLoc, Id, T,
|
||||
/*TInfo=*/0, // FIXME: Do ObjCAtDefs have declarators ?
|
||||
BW, /*Mutable=*/false, /*HasInit=*/false) {}
|
||||
BW, /*Mutable=*/false, /*HasInit=*/ICIS_NoInit) {}
|
||||
|
||||
public:
|
||||
static ObjCAtDefsFieldDecl *Create(ASTContext &C, DeclContext *DC,
|
||||
|
|
@ -1071,29 +1102,35 @@ public:
|
|||
static bool classofKind(Kind K) { return K == ObjCAtDefsField; }
|
||||
};
|
||||
|
||||
/// ObjCProtocolDecl - Represents a protocol declaration. ObjC protocols
|
||||
/// declare a pure abstract type (i.e no instance variables are permitted).
|
||||
/// Protocols originally drew inspiration from C++ pure virtual functions (a C++
|
||||
/// feature with nice semantics and lousy syntax:-). Here is an example:
|
||||
/// \brief Represents an Objective-C protocol declaration.
|
||||
///
|
||||
/// @protocol NSDraggingInfo <refproto1, refproto2>
|
||||
/// Objective-C protocols declare a pure abstract type (i.e., no instance
|
||||
/// variables are permitted). Protocols originally drew inspiration from
|
||||
/// C++ pure virtual functions (a C++ feature with nice semantics and lousy
|
||||
/// syntax:-). Here is an example:
|
||||
///
|
||||
/// \code
|
||||
/// \@protocol NSDraggingInfo <refproto1, refproto2>
|
||||
/// - (NSWindow *)draggingDestinationWindow;
|
||||
/// - (NSImage *)draggedImage;
|
||||
/// @end
|
||||
/// \@end
|
||||
/// \endcode
|
||||
///
|
||||
/// This says that NSDraggingInfo requires two methods and requires everything
|
||||
/// that the two "referenced protocols" 'refproto1' and 'refproto2' require as
|
||||
/// well.
|
||||
///
|
||||
/// @interface ImplementsNSDraggingInfo : NSObject <NSDraggingInfo>
|
||||
/// @end
|
||||
/// \code
|
||||
/// \@interface ImplementsNSDraggingInfo : NSObject \<NSDraggingInfo>
|
||||
/// \@end
|
||||
/// \endcode
|
||||
///
|
||||
/// ObjC protocols inspired Java interfaces. Unlike Java, ObjC classes and
|
||||
/// protocols are in distinct namespaces. For example, Cocoa defines both
|
||||
/// an NSObject protocol and class (which isn't allowed in Java). As a result,
|
||||
/// protocols are referenced using angle brackets as follows:
|
||||
///
|
||||
/// id <NSDraggingInfo> anyObjectThatImplementsNSDraggingInfo;
|
||||
/// id \<NSDraggingInfo> anyObjectThatImplementsNSDraggingInfo;
|
||||
///
|
||||
class ObjCProtocolDecl : public ObjCContainerDecl,
|
||||
public Redeclarable<ObjCProtocolDecl> {
|
||||
|
|
@ -1255,9 +1292,9 @@ public:
|
|||
/// you to add instance data. The following example adds "myMethod" to all
|
||||
/// NSView's within a process:
|
||||
///
|
||||
/// @interface NSView (MyViewMethods)
|
||||
/// \@interface NSView (MyViewMethods)
|
||||
/// - myMethod;
|
||||
/// @end
|
||||
/// \@end
|
||||
///
|
||||
/// Categories also allow you to split the implementation of a class across
|
||||
/// several files (a feature more naturally supported in C++).
|
||||
|
|
@ -1279,9 +1316,6 @@ class ObjCCategoryDecl : public ObjCContainerDecl {
|
|||
/// FIXME: this should not be a singly-linked list. Move storage elsewhere.
|
||||
ObjCCategoryDecl *NextClassCategory;
|
||||
|
||||
/// true of class extension has at least one bitfield ivar.
|
||||
bool HasSynthBitfield : 1;
|
||||
|
||||
/// \brief The location of the category name in this declaration.
|
||||
SourceLocation CategoryNameLoc;
|
||||
|
||||
|
|
@ -1295,7 +1329,7 @@ class ObjCCategoryDecl : public ObjCContainerDecl {
|
|||
SourceLocation IvarLBraceLoc=SourceLocation(),
|
||||
SourceLocation IvarRBraceLoc=SourceLocation())
|
||||
: ObjCContainerDecl(ObjCCategory, DC, Id, ClassNameLoc, AtLoc),
|
||||
ClassInterface(IDecl), NextClassCategory(0), HasSynthBitfield(false),
|
||||
ClassInterface(IDecl), NextClassCategory(0),
|
||||
CategoryNameLoc(CategoryNameLoc),
|
||||
IvarLBraceLoc(IvarLBraceLoc), IvarRBraceLoc(IvarRBraceLoc) {
|
||||
}
|
||||
|
|
@ -1345,9 +1379,6 @@ public:
|
|||
bool IsClassExtension() const { return getIdentifier() == 0; }
|
||||
const ObjCCategoryDecl *getNextClassExtension() const;
|
||||
|
||||
bool hasSynthBitfield() const { return HasSynthBitfield; }
|
||||
void setHasSynthBitfield (bool val) { HasSynthBitfield = val; }
|
||||
|
||||
typedef specific_decl_iterator<ObjCIvarDecl> ivar_iterator;
|
||||
ivar_iterator ivar_begin() const {
|
||||
return ivar_iterator(decls_begin());
|
||||
|
|
@ -1431,16 +1462,16 @@ public:
|
|||
};
|
||||
|
||||
/// ObjCCategoryImplDecl - An object of this class encapsulates a category
|
||||
/// @implementation declaration. If a category class has declaration of a
|
||||
/// \@implementation declaration. If a category class has declaration of a
|
||||
/// property, its implementation must be specified in the category's
|
||||
/// @implementation declaration. Example:
|
||||
/// @interface I @end
|
||||
/// @interface I(CATEGORY)
|
||||
/// @property int p1, d1;
|
||||
/// @end
|
||||
/// @implementation I(CATEGORY)
|
||||
/// @dynamic p1,d1;
|
||||
/// @end
|
||||
/// \@implementation declaration. Example:
|
||||
/// \@interface I \@end
|
||||
/// \@interface I(CATEGORY)
|
||||
/// \@property int p1, d1;
|
||||
/// \@end
|
||||
/// \@implementation I(CATEGORY)
|
||||
/// \@dynamic p1,d1;
|
||||
/// \@end
|
||||
///
|
||||
/// ObjCCategoryImplDecl
|
||||
class ObjCCategoryImplDecl : public ObjCImplDecl {
|
||||
|
|
@ -1493,15 +1524,6 @@ public:
|
|||
return Id ? Id->getNameStart() : "";
|
||||
}
|
||||
|
||||
/// getNameAsCString - Get the name of identifier for the class
|
||||
/// interface associated with this implementation as a C string
|
||||
/// (const char*).
|
||||
//
|
||||
// FIXME: Deprecated, move clients to getName().
|
||||
const char *getNameAsCString() const {
|
||||
return Id ? Id->getNameStart() : "";
|
||||
}
|
||||
|
||||
/// @brief Get the name of the class associated with this interface.
|
||||
//
|
||||
// FIXME: Deprecated, move clients to getName().
|
||||
|
|
@ -1523,9 +1545,9 @@ raw_ostream &operator<<(raw_ostream &OS, const ObjCCategoryImplDecl &CID);
|
|||
/// method definitions are specified. For example:
|
||||
///
|
||||
/// @code
|
||||
/// @implementation MyClass
|
||||
/// \@implementation MyClass
|
||||
/// - (void)myMethod { /* do something */ }
|
||||
/// @end
|
||||
/// \@end
|
||||
/// @endcode
|
||||
///
|
||||
/// Typically, instance variables are specified in the class interface,
|
||||
|
|
@ -1537,7 +1559,7 @@ class ObjCImplementationDecl : public ObjCImplDecl {
|
|||
virtual void anchor();
|
||||
/// Implementation Class's super class.
|
||||
ObjCInterfaceDecl *SuperClass;
|
||||
/// @implementation may have private ivars.
|
||||
/// \@implementation may have private ivars.
|
||||
SourceLocation IvarLBraceLoc;
|
||||
SourceLocation IvarRBraceLoc;
|
||||
|
||||
|
|
@ -1549,9 +1571,6 @@ class ObjCImplementationDecl : public ObjCImplDecl {
|
|||
/// true if class has a .cxx_[construct,destruct] method.
|
||||
bool HasCXXStructors : 1;
|
||||
|
||||
/// true of class extension has at least one bitfield ivar.
|
||||
bool HasSynthBitfield : 1;
|
||||
|
||||
ObjCImplementationDecl(DeclContext *DC,
|
||||
ObjCInterfaceDecl *classInterface,
|
||||
ObjCInterfaceDecl *superDecl,
|
||||
|
|
@ -1562,7 +1581,7 @@ class ObjCImplementationDecl : public ObjCImplDecl {
|
|||
SuperClass(superDecl), IvarLBraceLoc(IvarLBraceLoc),
|
||||
IvarRBraceLoc(IvarRBraceLoc),
|
||||
IvarInitializers(0), NumIvarInitializers(0),
|
||||
HasCXXStructors(false), HasSynthBitfield(false){}
|
||||
HasCXXStructors(false) {}
|
||||
public:
|
||||
static ObjCImplementationDecl *Create(ASTContext &C, DeclContext *DC,
|
||||
ObjCInterfaceDecl *classInterface,
|
||||
|
|
@ -1609,9 +1628,6 @@ public:
|
|||
bool hasCXXStructors() const { return HasCXXStructors; }
|
||||
void setHasCXXStructors(bool val) { HasCXXStructors = val; }
|
||||
|
||||
bool hasSynthBitfield() const { return HasSynthBitfield; }
|
||||
void setHasSynthBitfield (bool val) { HasSynthBitfield = val; }
|
||||
|
||||
/// getIdentifier - Get the identifier that names the class
|
||||
/// interface associated with this implementation.
|
||||
IdentifierInfo *getIdentifier() const {
|
||||
|
|
@ -1628,15 +1644,6 @@ public:
|
|||
return getIdentifier()->getName();
|
||||
}
|
||||
|
||||
/// getNameAsCString - Get the name of identifier for the class
|
||||
/// interface associated with this implementation as a C string
|
||||
/// (const char*).
|
||||
//
|
||||
// FIXME: Move to StringRef API.
|
||||
const char *getNameAsCString() const {
|
||||
return getName().data();
|
||||
}
|
||||
|
||||
/// @brief Get the name of the class associated with this interface.
|
||||
//
|
||||
// FIXME: Move to StringRef API.
|
||||
|
|
@ -1679,7 +1686,7 @@ public:
|
|||
raw_ostream &operator<<(raw_ostream &OS, const ObjCImplementationDecl &ID);
|
||||
|
||||
/// ObjCCompatibleAliasDecl - Represents alias of a class. This alias is
|
||||
/// declared as @compatibility_alias alias class.
|
||||
/// declared as \@compatibility_alias alias class.
|
||||
class ObjCCompatibleAliasDecl : public NamedDecl {
|
||||
virtual void anchor();
|
||||
/// Class that this is an alias of.
|
||||
|
|
@ -1706,10 +1713,12 @@ public:
|
|||
|
||||
};
|
||||
|
||||
/// ObjCPropertyDecl - Represents one property declaration in an interface.
|
||||
/// For example:
|
||||
/// @property (assign, readwrite) int MyProperty;
|
||||
/// \brief Represents one property declaration in an Objective-C interface.
|
||||
///
|
||||
/// For example:
|
||||
/// \code{.mm}
|
||||
/// \@property (assign, readwrite) int MyProperty;
|
||||
/// \endcode
|
||||
class ObjCPropertyDecl : public NamedDecl {
|
||||
virtual void anchor();
|
||||
public:
|
||||
|
|
@ -1738,12 +1747,12 @@ public:
|
|||
enum SetterKind { Assign, Retain, Copy, Weak };
|
||||
enum PropertyControl { None, Required, Optional };
|
||||
private:
|
||||
SourceLocation AtLoc; // location of @property
|
||||
SourceLocation AtLoc; // location of \@property
|
||||
SourceLocation LParenLoc; // location of '(' starting attribute list or null.
|
||||
TypeSourceInfo *DeclType;
|
||||
unsigned PropertyAttributes : NumPropertyAttrsBits;
|
||||
unsigned PropertyAttributesAsWritten : NumPropertyAttrsBits;
|
||||
// @required/@optional
|
||||
// \@required/\@optional
|
||||
unsigned PropertyImplementation : 2;
|
||||
|
||||
Selector GetterName; // getter name of NULL if no getter
|
||||
|
|
@ -1855,7 +1864,7 @@ public:
|
|||
ObjCMethodDecl *getSetterMethodDecl() const { return SetterMethodDecl; }
|
||||
void setSetterMethodDecl(ObjCMethodDecl *gDecl) { SetterMethodDecl = gDecl; }
|
||||
|
||||
// Related to @optional/@required declared in @protocol
|
||||
// Related to \@optional/\@required declared in \@protocol
|
||||
void setPropertyImplementation(PropertyControl pc) {
|
||||
PropertyImplementation = pc;
|
||||
}
|
||||
|
|
@ -1885,7 +1894,7 @@ public:
|
|||
|
||||
/// ObjCPropertyImplDecl - Represents implementation declaration of a property
|
||||
/// in a class or category implementation block. For example:
|
||||
/// @synthesize prop1 = ivar1;
|
||||
/// \@synthesize prop1 = ivar1;
|
||||
///
|
||||
class ObjCPropertyImplDecl : public Decl {
|
||||
public:
|
||||
|
|
@ -1894,26 +1903,27 @@ public:
|
|||
Dynamic
|
||||
};
|
||||
private:
|
||||
SourceLocation AtLoc; // location of @synthesize or @dynamic
|
||||
SourceLocation AtLoc; // location of \@synthesize or \@dynamic
|
||||
|
||||
/// \brief For @synthesize, the location of the ivar, if it was written in
|
||||
/// \brief For \@synthesize, the location of the ivar, if it was written in
|
||||
/// the source code.
|
||||
///
|
||||
/// \code
|
||||
/// @synthesize int a = b
|
||||
/// \@synthesize int a = b
|
||||
/// \endcode
|
||||
SourceLocation IvarLoc;
|
||||
|
||||
/// Property declaration being implemented
|
||||
ObjCPropertyDecl *PropertyDecl;
|
||||
|
||||
/// Null for @dynamic. Required for @synthesize.
|
||||
/// Null for \@dynamic. Required for \@synthesize.
|
||||
ObjCIvarDecl *PropertyIvarDecl;
|
||||
|
||||
/// Null for @dynamic. Non-null if property must be copy-constructed in getter
|
||||
/// Null for \@dynamic. Non-null if property must be copy-constructed in
|
||||
/// getter.
|
||||
Expr *GetterCXXConstructor;
|
||||
|
||||
/// Null for @dynamic. Non-null if property has assignment operator to call
|
||||
/// Null for \@dynamic. Non-null if property has assignment operator to call
|
||||
/// in Setter synthesis.
|
||||
Expr *SetterCXXAssignment;
|
||||
|
||||
|
|
@ -1963,6 +1973,17 @@ public:
|
|||
this->IvarLoc = IvarLoc;
|
||||
}
|
||||
|
||||
/// \brief For \@synthesize, returns true if an ivar name was explicitly
|
||||
/// specified.
|
||||
///
|
||||
/// \code
|
||||
/// \@synthesize int a = b; // true
|
||||
/// \@synthesize int a; // false
|
||||
/// \endcode
|
||||
bool isIvarNameSpecified() const {
|
||||
return IvarLoc.isValid() && IvarLoc != getLocation();
|
||||
}
|
||||
|
||||
Expr *getGetterCXXConstructor() const {
|
||||
return GetterCXXConstructor;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,9 +6,10 @@
|
|||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the C++ template declaration subclasses.
|
||||
//
|
||||
///
|
||||
/// \file
|
||||
/// \brief Defines the C++ template declaration subclasses.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_DECLTEMPLATE_H
|
||||
|
|
@ -38,8 +39,8 @@ class TypeAliasTemplateDecl;
|
|||
typedef llvm::PointerUnion3<TemplateTypeParmDecl*, NonTypeTemplateParmDecl*,
|
||||
TemplateTemplateParmDecl*> TemplateParameter;
|
||||
|
||||
/// TemplateParameterList - Stores a list of template parameters for a
|
||||
/// TemplateDecl and its derived classes.
|
||||
/// \brief Stores a list of template parameters for a TemplateDecl and its
|
||||
/// derived classes.
|
||||
class TemplateParameterList {
|
||||
/// The location of the 'template' keyword.
|
||||
SourceLocation TemplateLoc;
|
||||
|
|
@ -64,10 +65,10 @@ public:
|
|||
unsigned NumParams,
|
||||
SourceLocation RAngleLoc);
|
||||
|
||||
/// iterator - Iterates through the template parameters in this list.
|
||||
/// \brief Iterates through the template parameters in this list.
|
||||
typedef NamedDecl** iterator;
|
||||
|
||||
/// const_iterator - Iterates through the template parameters in this list.
|
||||
/// \brief Iterates through the template parameters in this list.
|
||||
typedef NamedDecl* const* const_iterator;
|
||||
|
||||
iterator begin() { return reinterpret_cast<NamedDecl **>(this + 1); }
|
||||
|
|
@ -90,9 +91,10 @@ public:
|
|||
}
|
||||
|
||||
/// \brief Returns the minimum number of arguments needed to form a
|
||||
/// template specialization. This may be fewer than the number of
|
||||
/// template parameters, if some of the parameters have default
|
||||
/// arguments or if there is a parameter pack.
|
||||
/// template specialization.
|
||||
///
|
||||
/// This may be fewer than the number of template parameters, if some of
|
||||
/// the parameters have default arguments or if there is a parameter pack.
|
||||
unsigned getMinRequiredArguments() const;
|
||||
|
||||
/// \brief Get the depth of this template parameter list in the set of
|
||||
|
|
@ -111,8 +113,8 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
/// FixedSizeTemplateParameterList - Stores a list of template parameters for a
|
||||
/// TemplateDecl and its derived classes. Suitable for creating on the stack.
|
||||
/// \brief Stores a list of template parameters for a TemplateDecl and its
|
||||
/// derived classes. Suitable for creating on the stack.
|
||||
template<size_t N>
|
||||
class FixedSizeTemplateParameterList : public TemplateParameterList {
|
||||
NamedDecl *Params[N];
|
||||
|
|
@ -195,10 +197,11 @@ public:
|
|||
// Kinds of Templates
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// TemplateDecl - The base class of all kinds of template declarations (e.g.,
|
||||
/// class, function, etc.). The TemplateDecl class stores the list of template
|
||||
/// parameters and a reference to the templated scoped declaration: the
|
||||
/// underlying AST node.
|
||||
/// \brief The base class of all kinds of template declarations (e.g.,
|
||||
/// class, function, etc.).
|
||||
///
|
||||
/// The TemplateDecl class stores the list of template parameters and a
|
||||
/// reference to the templated scoped declaration: the underlying AST node.
|
||||
class TemplateDecl : public NamedDecl {
|
||||
virtual void anchor();
|
||||
protected:
|
||||
|
|
@ -404,16 +407,19 @@ public:
|
|||
};
|
||||
|
||||
/// \brief Provides information about a dependent function-template
|
||||
/// specialization declaration. Since explicit function template
|
||||
/// specialization and instantiation declarations can only appear in
|
||||
/// namespace scope, and you can only specialize a member of a
|
||||
/// fully-specialized class, the only way to get one of these is in
|
||||
/// a friend declaration like the following:
|
||||
/// specialization declaration.
|
||||
///
|
||||
/// template <class T> void foo(T);
|
||||
/// template <class T> class A {
|
||||
/// Since explicit function template specialization and instantiation
|
||||
/// declarations can only appear in namespace scope, and you can only
|
||||
/// specialize a member of a fully-specialized class, the only way to
|
||||
/// get one of these is in a friend declaration like the following:
|
||||
///
|
||||
/// \code
|
||||
/// template \<class T> void foo(T);
|
||||
/// template \<class T> class A {
|
||||
/// friend void foo<>(T);
|
||||
/// };
|
||||
/// \endcode
|
||||
class DependentFunctionTemplateSpecializationInfo {
|
||||
union {
|
||||
// Force sizeof to be a multiple of sizeof(void*) so that the
|
||||
|
|
@ -512,7 +518,8 @@ protected:
|
|||
typedef _SETraits SETraits;
|
||||
typedef _DeclType DeclType;
|
||||
|
||||
typedef typename llvm::FoldingSet<EntryType>::iterator SetIteratorType;
|
||||
typedef typename llvm::FoldingSetVector<EntryType>::iterator
|
||||
SetIteratorType;
|
||||
|
||||
SetIteratorType SetIter;
|
||||
|
||||
|
|
@ -541,13 +548,13 @@ protected:
|
|||
};
|
||||
|
||||
template <typename EntryType>
|
||||
SpecIterator<EntryType> makeSpecIterator(llvm::FoldingSet<EntryType> &Specs,
|
||||
bool isEnd) {
|
||||
SpecIterator<EntryType>
|
||||
makeSpecIterator(llvm::FoldingSetVector<EntryType> &Specs, bool isEnd) {
|
||||
return SpecIterator<EntryType>(isEnd ? Specs.end() : Specs.begin());
|
||||
}
|
||||
|
||||
template <class EntryType> typename SpecEntryTraits<EntryType>::DeclType*
|
||||
findSpecializationImpl(llvm::FoldingSet<EntryType> &Specs,
|
||||
findSpecializationImpl(llvm::FoldingSetVector<EntryType> &Specs,
|
||||
const TemplateArgument *Args, unsigned NumArgs,
|
||||
void *&InsertPos);
|
||||
|
||||
|
|
@ -583,7 +590,7 @@ protected:
|
|||
public:
|
||||
template <class decl_type> friend class RedeclarableTemplate;
|
||||
|
||||
/// Retrieves the canonical declaration of this template.
|
||||
/// \brief Retrieves the canonical declaration of this template.
|
||||
RedeclarableTemplateDecl *getCanonicalDecl() { return getFirstDeclaration(); }
|
||||
const RedeclarableTemplateDecl *getCanonicalDecl() const {
|
||||
return getFirstDeclaration();
|
||||
|
|
@ -646,7 +653,7 @@ public:
|
|||
///
|
||||
/// which was itself created during the instantiation of \c X<int>. Calling
|
||||
/// getInstantiatedFromMemberTemplate() on this FunctionTemplateDecl will
|
||||
/// retrieve the FunctionTemplateDecl for the original template "f" within
|
||||
/// retrieve the FunctionTemplateDecl for the original template \c f within
|
||||
/// the class template \c X<T>, i.e.,
|
||||
///
|
||||
/// \code
|
||||
|
|
@ -706,7 +713,7 @@ protected:
|
|||
|
||||
/// \brief The function template specializations for this function
|
||||
/// template, including explicit specializations and instantiations.
|
||||
llvm::FoldingSet<FunctionTemplateSpecializationInfo> Specializations;
|
||||
llvm::FoldingSetVector<FunctionTemplateSpecializationInfo> Specializations;
|
||||
|
||||
/// \brief The set of "injected" template arguments used within this
|
||||
/// function template.
|
||||
|
|
@ -732,13 +739,14 @@ protected:
|
|||
|
||||
/// \brief Retrieve the set of function template specializations of this
|
||||
/// function template.
|
||||
llvm::FoldingSet<FunctionTemplateSpecializationInfo> &getSpecializations() {
|
||||
llvm::FoldingSetVector<FunctionTemplateSpecializationInfo> &
|
||||
getSpecializations() {
|
||||
return getCommonPtr()->Specializations;
|
||||
}
|
||||
|
||||
/// \brief Add a specialization of this function template.
|
||||
///
|
||||
/// \param InsertPos Insert position in the FoldingSet, must have been
|
||||
/// \param InsertPos Insert position in the FoldingSetVector, must have been
|
||||
/// retrieved by an earlier call to findSpecialization().
|
||||
void addSpecialization(FunctionTemplateSpecializationInfo* Info,
|
||||
void *InsertPos);
|
||||
|
|
@ -830,8 +838,10 @@ public:
|
|||
// Kinds of Template Parameters
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// The TemplateParmPosition class defines the position of a template parameter
|
||||
/// within a template parameter list. Because template parameter can be listed
|
||||
/// \brief Defines the position of a template parameter within a template
|
||||
/// parameter list.
|
||||
///
|
||||
/// Because template parameter can be listed
|
||||
/// sequentially for out-of-line template members, each template parameter is
|
||||
/// given a Depth - the nesting of template parameter scopes - and a Position -
|
||||
/// the occurrence within the parameter list.
|
||||
|
|
@ -866,15 +876,17 @@ public:
|
|||
unsigned getIndex() const { return Position; }
|
||||
};
|
||||
|
||||
/// TemplateTypeParmDecl - Declaration of a template type parameter,
|
||||
/// e.g., "T" in
|
||||
/// @code
|
||||
/// \brief Declaration of a template type parameter.
|
||||
///
|
||||
/// For example, "T" in
|
||||
/// \code
|
||||
/// template<typename T> class vector;
|
||||
/// @endcode
|
||||
/// \endcode
|
||||
class TemplateTypeParmDecl : public TypeDecl {
|
||||
/// \brief Whether this template type parameter was declaration with
|
||||
/// the 'typename' keyword. If false, it was declared with the
|
||||
/// 'class' keyword.
|
||||
/// the 'typename' keyword.
|
||||
///
|
||||
/// If false, it was declared with the 'class' keyword.
|
||||
bool Typename : 1;
|
||||
|
||||
/// \brief Whether this template type parameter inherited its
|
||||
|
|
@ -904,8 +916,9 @@ public:
|
|||
unsigned ID);
|
||||
|
||||
/// \brief Whether this template type parameter was declared with
|
||||
/// the 'typename' keyword. If not, it was declared with the 'class'
|
||||
/// keyword.
|
||||
/// the 'typename' keyword.
|
||||
///
|
||||
/// If not, it was declared with the 'class' keyword.
|
||||
bool wasDeclaredWithTypename() const { return Typename; }
|
||||
|
||||
/// \brief Determine whether this template parameter has a default
|
||||
|
|
@ -1688,11 +1701,11 @@ protected:
|
|||
|
||||
/// \brief The class template specializations for this class
|
||||
/// template, including explicit specializations and instantiations.
|
||||
llvm::FoldingSet<ClassTemplateSpecializationDecl> Specializations;
|
||||
llvm::FoldingSetVector<ClassTemplateSpecializationDecl> Specializations;
|
||||
|
||||
/// \brief The class template partial specializations for this class
|
||||
/// template.
|
||||
llvm::FoldingSet<ClassTemplatePartialSpecializationDecl>
|
||||
llvm::FoldingSetVector<ClassTemplatePartialSpecializationDecl>
|
||||
PartialSpecializations;
|
||||
|
||||
/// \brief The injected-class-name type for this class template.
|
||||
|
|
@ -1710,11 +1723,11 @@ protected:
|
|||
void LoadLazySpecializations();
|
||||
|
||||
/// \brief Retrieve the set of specializations of this class template.
|
||||
llvm::FoldingSet<ClassTemplateSpecializationDecl> &getSpecializations();
|
||||
llvm::FoldingSetVector<ClassTemplateSpecializationDecl> &getSpecializations();
|
||||
|
||||
/// \brief Retrieve the set of partial specializations of this class
|
||||
/// template.
|
||||
llvm::FoldingSet<ClassTemplatePartialSpecializationDecl> &
|
||||
llvm::FoldingSetVector<ClassTemplatePartialSpecializationDecl> &
|
||||
getPartialSpecializations();
|
||||
|
||||
ClassTemplateDecl(DeclContext *DC, SourceLocation L, DeclarationName Name,
|
||||
|
|
@ -1732,18 +1745,18 @@ protected:
|
|||
}
|
||||
|
||||
public:
|
||||
/// Get the underlying class declarations of the template.
|
||||
/// \brief Get the underlying class declarations of the template.
|
||||
CXXRecordDecl *getTemplatedDecl() const {
|
||||
return static_cast<CXXRecordDecl *>(TemplatedDecl);
|
||||
}
|
||||
|
||||
/// Returns whether this template declaration defines the primary
|
||||
/// \brief Returns whether this template declaration defines the primary
|
||||
/// class pattern.
|
||||
bool isThisDeclarationADefinition() const {
|
||||
return getTemplatedDecl()->isThisDeclarationADefinition();
|
||||
}
|
||||
|
||||
/// Create a class template node.
|
||||
/// \brief Create a class template node.
|
||||
static ClassTemplateDecl *Create(ASTContext &C, DeclContext *DC,
|
||||
SourceLocation L,
|
||||
DeclarationName Name,
|
||||
|
|
@ -1751,7 +1764,7 @@ public:
|
|||
NamedDecl *Decl,
|
||||
ClassTemplateDecl *PrevDecl);
|
||||
|
||||
/// Create an empty class template node.
|
||||
/// \brief Create an empty class template node.
|
||||
static ClassTemplateDecl *CreateDeserialized(ASTContext &C, unsigned ID);
|
||||
|
||||
/// \brief Return the specialization with the provided arguments if it exists,
|
||||
|
|
@ -1880,14 +1893,18 @@ public:
|
|||
friend class ASTDeclWriter;
|
||||
};
|
||||
|
||||
/// Declaration of a friend template. For example:
|
||||
/// \brief Declaration of a friend template.
|
||||
///
|
||||
/// template <typename T> class A {
|
||||
/// For example:
|
||||
/// \code
|
||||
/// template \<typename T> class A {
|
||||
/// friend class MyVector<T>; // not a friend template
|
||||
/// template <typename U> friend class B; // not a friend template
|
||||
/// template <typename U> friend class Foo<T>::Nested; // friend template
|
||||
/// template \<typename U> friend class B; // not a friend template
|
||||
/// template \<typename U> friend class Foo<T>::Nested; // friend template
|
||||
/// };
|
||||
/// NOTE: This class is not currently in use. All of the above
|
||||
/// \endcode
|
||||
///
|
||||
/// \note This class is not currently in use. All of the above
|
||||
/// will yield a FriendDecl, not a FriendTemplateDecl.
|
||||
class FriendTemplateDecl : public Decl {
|
||||
virtual void anchor();
|
||||
|
|
@ -1950,7 +1967,7 @@ public:
|
|||
return Friend.dyn_cast<NamedDecl*>();
|
||||
}
|
||||
|
||||
/// Retrieves the location of the 'friend' keyword.
|
||||
/// \brief Retrieves the location of the 'friend' keyword.
|
||||
SourceLocation getFriendLoc() const {
|
||||
return FriendLoc;
|
||||
}
|
||||
|
|
@ -1972,9 +1989,12 @@ public:
|
|||
friend class ASTDeclReader;
|
||||
};
|
||||
|
||||
/// Declaration of an alias template. For example:
|
||||
/// \brief Declaration of an alias template.
|
||||
///
|
||||
/// template <typename T> using V = std::map<T*, int, MyCompare<T>>;
|
||||
/// For example:
|
||||
/// \code
|
||||
/// template \<typename T> using V = std::map<T*, int, MyCompare<T>>;
|
||||
/// \endcode
|
||||
class TypeAliasTemplateDecl : public RedeclarableTemplateDecl {
|
||||
static void DeallocateCommon(void *Ptr);
|
||||
|
||||
|
|
@ -2046,14 +2066,18 @@ public:
|
|||
friend class ASTDeclWriter;
|
||||
};
|
||||
|
||||
/// Declaration of a function specialization at template class scope.
|
||||
/// \brief Declaration of a function specialization at template class scope.
|
||||
///
|
||||
/// This is a non standard extension needed to support MSVC.
|
||||
///
|
||||
/// For example:
|
||||
/// \code
|
||||
/// template <class T>
|
||||
/// class A {
|
||||
/// template <class U> void foo(U a) { }
|
||||
/// template<> void foo(int a) { }
|
||||
/// }
|
||||
/// \endcode
|
||||
///
|
||||
/// "template<> foo(int a)" will be saved in Specialization as a normal
|
||||
/// CXXMethodDecl. Then during an instantiation of class A, it will be
|
||||
|
|
@ -2062,23 +2086,33 @@ class ClassScopeFunctionSpecializationDecl : public Decl {
|
|||
virtual void anchor();
|
||||
|
||||
ClassScopeFunctionSpecializationDecl(DeclContext *DC, SourceLocation Loc,
|
||||
CXXMethodDecl *FD)
|
||||
CXXMethodDecl *FD, bool Args,
|
||||
TemplateArgumentListInfo TemplArgs)
|
||||
: Decl(Decl::ClassScopeFunctionSpecialization, DC, Loc),
|
||||
Specialization(FD) {}
|
||||
Specialization(FD), HasExplicitTemplateArgs(Args),
|
||||
TemplateArgs(TemplArgs) {}
|
||||
|
||||
ClassScopeFunctionSpecializationDecl(EmptyShell Empty)
|
||||
: Decl(Decl::ClassScopeFunctionSpecialization, Empty) {}
|
||||
|
||||
CXXMethodDecl *Specialization;
|
||||
bool HasExplicitTemplateArgs;
|
||||
TemplateArgumentListInfo TemplateArgs;
|
||||
|
||||
public:
|
||||
CXXMethodDecl *getSpecialization() const { return Specialization; }
|
||||
bool hasExplicitTemplateArgs() const { return HasExplicitTemplateArgs; }
|
||||
const TemplateArgumentListInfo& templateArgs() const { return TemplateArgs; }
|
||||
|
||||
static ClassScopeFunctionSpecializationDecl *Create(ASTContext &C,
|
||||
DeclContext *DC,
|
||||
SourceLocation Loc,
|
||||
CXXMethodDecl *FD) {
|
||||
return new (C) ClassScopeFunctionSpecializationDecl(DC , Loc, FD);
|
||||
CXXMethodDecl *FD,
|
||||
bool HasExplicitTemplateArgs,
|
||||
TemplateArgumentListInfo TemplateArgs) {
|
||||
return new (C) ClassScopeFunctionSpecializationDecl(DC , Loc, FD,
|
||||
HasExplicitTemplateArgs,
|
||||
TemplateArgs);
|
||||
}
|
||||
|
||||
static ClassScopeFunctionSpecializationDecl *
|
||||
|
|
|
|||
|
|
@ -58,11 +58,14 @@ public:
|
|||
private:
|
||||
/// StoredNameKind - The kind of name that is actually stored in the
|
||||
/// upper bits of the Ptr field. This is only used internally.
|
||||
///
|
||||
/// Note: The entries here are synchronized with the entries in Selector,
|
||||
/// for efficient translation between the two.
|
||||
enum StoredNameKind {
|
||||
StoredIdentifier = 0,
|
||||
StoredObjCZeroArgSelector,
|
||||
StoredObjCOneArgSelector,
|
||||
StoredDeclarationNameExtra,
|
||||
StoredObjCZeroArgSelector = 0x01,
|
||||
StoredObjCOneArgSelector = 0x02,
|
||||
StoredDeclarationNameExtra = 0x03,
|
||||
PtrMask = 0x03
|
||||
};
|
||||
|
||||
|
|
@ -106,8 +109,8 @@ private:
|
|||
/// CXXSpecialName, returns a pointer to it. Otherwise, returns
|
||||
/// a NULL pointer.
|
||||
CXXSpecialName *getAsCXXSpecialName() const {
|
||||
if (getNameKind() >= CXXConstructorName &&
|
||||
getNameKind() <= CXXConversionFunctionName)
|
||||
NameKind Kind = getNameKind();
|
||||
if (Kind >= CXXConstructorName && Kind <= CXXConversionFunctionName)
|
||||
return reinterpret_cast<CXXSpecialName *>(Ptr & ~PtrMask);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -153,9 +156,9 @@ private:
|
|||
friend class DeclarationNameTable;
|
||||
friend class NamedDecl;
|
||||
|
||||
/// getFETokenInfoAsVoid - Retrieves the front end-specified pointer
|
||||
/// for this name as a void pointer.
|
||||
void *getFETokenInfoAsVoid() const;
|
||||
/// getFETokenInfoAsVoidSlow - Retrieves the front end-specified pointer
|
||||
/// for this name as a void pointer if it's not an identifier.
|
||||
void *getFETokenInfoAsVoidSlow() const;
|
||||
|
||||
public:
|
||||
/// DeclarationName - Used to create an empty selector.
|
||||
|
|
@ -168,7 +171,7 @@ public:
|
|||
}
|
||||
|
||||
// Construct a declaration name from an Objective-C selector.
|
||||
DeclarationName(Selector Sel);
|
||||
DeclarationName(Selector Sel) : Ptr(Sel.InfoPtr) { }
|
||||
|
||||
/// getUsingDirectiveName - Return name for all using-directives.
|
||||
static DeclarationName getUsingDirectiveName();
|
||||
|
|
@ -251,14 +254,24 @@ public:
|
|||
|
||||
/// getObjCSelector - Get the Objective-C selector stored in this
|
||||
/// declaration name.
|
||||
Selector getObjCSelector() const;
|
||||
Selector getObjCSelector() const {
|
||||
assert((getNameKind() == ObjCZeroArgSelector ||
|
||||
getNameKind() == ObjCOneArgSelector ||
|
||||
getNameKind() == ObjCMultiArgSelector ||
|
||||
Ptr == 0) && "Not a selector!");
|
||||
return Selector(Ptr);
|
||||
}
|
||||
|
||||
/// getFETokenInfo/setFETokenInfo - The language front-end is
|
||||
/// allowed to associate arbitrary metadata with some kinds of
|
||||
/// declaration names, including normal identifiers and C++
|
||||
/// constructors, destructors, and conversion functions.
|
||||
template<typename T>
|
||||
T *getFETokenInfo() const { return static_cast<T*>(getFETokenInfoAsVoid()); }
|
||||
T *getFETokenInfo() const {
|
||||
if (const IdentifierInfo *Info = getAsIdentifierInfo())
|
||||
return Info->getFETokenInfo<T>();
|
||||
return static_cast<T*>(getFETokenInfoAsVoidSlow());
|
||||
}
|
||||
|
||||
void setFETokenInfo(void *T);
|
||||
|
||||
|
|
@ -564,7 +577,9 @@ struct DenseMapInfo<clang::DeclarationName> {
|
|||
return clang::DeclarationName::getTombstoneMarker();
|
||||
}
|
||||
|
||||
static unsigned getHashValue(clang::DeclarationName);
|
||||
static unsigned getHashValue(clang::DeclarationName Name) {
|
||||
return DenseMapInfo<void*>::getHashValue(Name.getAsOpaquePtr());
|
||||
}
|
||||
|
||||
static inline bool
|
||||
isEqual(clang::DeclarationName LHS, clang::DeclarationName RHS) {
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ namespace clang {
|
|||
|
||||
class ASTContext;
|
||||
|
||||
/// \begin Given a potentially-evaluated expression, this visitor visits all
|
||||
/// \brief Given a potentially-evaluated expression, this visitor visits all
|
||||
/// of its potentially-evaluated subexpressions, recursively.
|
||||
template<typename ImplClass>
|
||||
class EvaluatedExprVisitor : public StmtVisitor<ImplClass> {
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
#define LLVM_CLANG_AST_EXPR_H
|
||||
|
||||
#include "clang/AST/APValue.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/Stmt.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/AST/DeclAccessPair.h"
|
||||
|
|
@ -179,11 +180,12 @@ public:
|
|||
SourceLocation getExprLoc() const LLVM_READONLY;
|
||||
|
||||
/// isUnusedResultAWarning - Return true if this immediate expression should
|
||||
/// be warned about if the result is unused. If so, fill in Loc and Ranges
|
||||
/// with location to warn on and the source range[s] to report with the
|
||||
/// warning.
|
||||
bool isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1,
|
||||
SourceRange &R2, ASTContext &Ctx) const;
|
||||
/// be warned about if the result is unused. If so, fill in expr, location,
|
||||
/// and ranges with expr to warn on and source locations/ranges appropriate
|
||||
/// for a warning.
|
||||
bool isUnusedResultAWarning(const Expr *&WarnExpr, SourceLocation &Loc,
|
||||
SourceRange &R1, SourceRange &R2,
|
||||
ASTContext &Ctx) const;
|
||||
|
||||
/// isLValue - True if this expression is an "l-value" according to
|
||||
/// the rules of the current language. C and C++ give somewhat
|
||||
|
|
@ -212,7 +214,8 @@ public:
|
|||
LV_InvalidMessageExpression,
|
||||
LV_MemberFunction,
|
||||
LV_SubObjCPropertySetting,
|
||||
LV_ClassTemporary
|
||||
LV_ClassTemporary,
|
||||
LV_ArrayTemporary
|
||||
};
|
||||
/// Reasons why an expression might not be an l-value.
|
||||
LValueClassification ClassifyLValue(ASTContext &Ctx) const;
|
||||
|
|
@ -223,7 +226,7 @@ public:
|
|||
/// 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
|
||||
/// \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 {
|
||||
|
|
@ -241,7 +244,8 @@ public:
|
|||
MLV_MemberFunction,
|
||||
MLV_SubObjCPropertySetting,
|
||||
MLV_InvalidMessageExpression,
|
||||
MLV_ClassTemporary
|
||||
MLV_ClassTemporary,
|
||||
MLV_ArrayTemporary
|
||||
};
|
||||
isModifiableLvalueResult isModifiableLvalue(ASTContext &Ctx,
|
||||
SourceLocation *Loc = 0) const;
|
||||
|
|
@ -260,7 +264,8 @@ public:
|
|||
CL_DuplicateVectorComponents, // A vector shuffle with dupes.
|
||||
CL_MemberFunction, // An expression referring to a member function
|
||||
CL_SubObjCPropertySetting,
|
||||
CL_ClassTemporary, // A prvalue of class type
|
||||
CL_ClassTemporary, // A temporary of class type, or subobject thereof.
|
||||
CL_ArrayTemporary, // A temporary of array type.
|
||||
CL_ObjCMessageRValue, // ObjC message is an rvalue
|
||||
CL_PRValue // A prvalue for any other reason, of any other type
|
||||
};
|
||||
|
|
@ -505,9 +510,8 @@ public:
|
|||
bool isEvaluatable(const ASTContext &Ctx) const;
|
||||
|
||||
/// HasSideEffects - This routine returns true for all those expressions
|
||||
/// which must be evaluated each time and must not be optimized away
|
||||
/// or evaluated at compile time. Example is a function call, volatile
|
||||
/// variable read.
|
||||
/// which have any effect other than producing a value. Example is a function
|
||||
/// call, volatile variable read, or throwing an exception.
|
||||
bool HasSideEffects(const ASTContext &Ctx) const;
|
||||
|
||||
/// \brief Determine whether this expression involves a call to any function
|
||||
|
|
@ -537,8 +541,15 @@ public:
|
|||
/// \brief Expression is not a Null pointer constant.
|
||||
NPCK_NotNull = 0,
|
||||
|
||||
/// \brief Expression is a Null pointer constant built from a zero integer.
|
||||
NPCK_ZeroInteger,
|
||||
/// \brief Expression is a Null pointer constant built from a zero integer
|
||||
/// expression that is not a simple, possibly parenthesized, zero literal.
|
||||
/// C++ Core Issue 903 will classify these expressions as "not pointers"
|
||||
/// once it is adopted.
|
||||
/// http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#903
|
||||
NPCK_ZeroExpression,
|
||||
|
||||
/// \brief Expression is a Null pointer constant built from a literal zero.
|
||||
NPCK_ZeroLiteral,
|
||||
|
||||
/// \brief Expression is a C++0X nullptr.
|
||||
NPCK_CXX0X_nullptr,
|
||||
|
|
@ -591,6 +602,10 @@ public:
|
|||
return cast<Expr>(Stmt::IgnoreImplicit());
|
||||
}
|
||||
|
||||
const Expr *IgnoreImplicit() const LLVM_READONLY {
|
||||
return const_cast<Expr*>(this)->IgnoreImplicit();
|
||||
}
|
||||
|
||||
/// IgnoreParens - Ignore parentheses. If this Expr is a ParenExpr, return
|
||||
/// its subexpression. If that subexpression is also a ParenExpr,
|
||||
/// then this method recursively returns its subexpression, and so forth.
|
||||
|
|
@ -630,6 +645,13 @@ public:
|
|||
/// ParenExpr or CastExprs, returning their operand.
|
||||
Expr *IgnoreParenNoopCasts(ASTContext &Ctx) LLVM_READONLY;
|
||||
|
||||
/// Ignore parentheses and derived-to-base casts.
|
||||
Expr *ignoreParenBaseCasts() LLVM_READONLY;
|
||||
|
||||
const Expr *ignoreParenBaseCasts() const LLVM_READONLY {
|
||||
return const_cast<Expr*>(this)->ignoreParenBaseCasts();
|
||||
}
|
||||
|
||||
/// \brief Determine whether this expression is a default function argument.
|
||||
///
|
||||
/// Default arguments are implicitly generated in the abstract syntax tree
|
||||
|
|
@ -661,6 +683,15 @@ public:
|
|||
|
||||
static bool hasAnyTypeDependentArguments(llvm::ArrayRef<Expr *> Exprs);
|
||||
|
||||
/// \brief For an expression of class type or pointer to class type,
|
||||
/// return the most derived class decl the expression is known to refer to.
|
||||
///
|
||||
/// If this expression is a cast, this method looks through it to find the
|
||||
/// most derived decl that can be inferred from the expression.
|
||||
/// This is valid because derived-to-base conversions have undefined
|
||||
/// behavior if the object isn't dynamically of the derived type.
|
||||
const CXXRecordDecl *getBestDynamicClassType() const;
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() >= firstExprConstant &&
|
||||
T->getStmtClass() <= lastExprConstant;
|
||||
|
|
@ -1043,6 +1074,7 @@ public:
|
|||
enum IdentType {
|
||||
Func,
|
||||
Function,
|
||||
LFunction, // Same as Function, but as wide string.
|
||||
PrettyFunction,
|
||||
/// PrettyFunctionNoVirtual - The same as PrettyFunction, except that the
|
||||
/// 'virtual' keyword is omitted for virtual member functions.
|
||||
|
|
@ -1142,16 +1174,8 @@ class IntegerLiteral : public Expr, public APIntStorage {
|
|||
public:
|
||||
// type should be IntTy, LongTy, LongLongTy, UnsignedIntTy, UnsignedLongTy,
|
||||
// or UnsignedLongLongTy
|
||||
IntegerLiteral(ASTContext &C, const llvm::APInt &V,
|
||||
QualType type, SourceLocation l)
|
||||
: Expr(IntegerLiteralClass, type, VK_RValue, OK_Ordinary, false, false,
|
||||
false, false),
|
||||
Loc(l) {
|
||||
assert(type->isIntegerType() && "Illegal type in IntegerLiteral");
|
||||
assert(V.getBitWidth() == C.getIntWidth(type) &&
|
||||
"Integer type is not the correct size for constant.");
|
||||
setValue(C, V);
|
||||
}
|
||||
IntegerLiteral(ASTContext &C, const llvm::APInt &V, QualType type,
|
||||
SourceLocation l);
|
||||
|
||||
/// \brief Returns a new integer literal with value 'V' and type 'type'.
|
||||
/// \param type - either IntTy, LongTy, LongLongTy, UnsignedIntTy,
|
||||
|
|
@ -1229,22 +1253,10 @@ class FloatingLiteral : public Expr, private APFloatStorage {
|
|||
SourceLocation Loc;
|
||||
|
||||
FloatingLiteral(ASTContext &C, const llvm::APFloat &V, bool isexact,
|
||||
QualType Type, SourceLocation L)
|
||||
: Expr(FloatingLiteralClass, Type, VK_RValue, OK_Ordinary, false, false,
|
||||
false, false), Loc(L) {
|
||||
FloatingLiteralBits.IsIEEE =
|
||||
&C.getTargetInfo().getLongDoubleFormat() == &llvm::APFloat::IEEEquad;
|
||||
FloatingLiteralBits.IsExact = isexact;
|
||||
setValue(C, V);
|
||||
}
|
||||
QualType Type, SourceLocation L);
|
||||
|
||||
/// \brief Construct an empty floating-point literal.
|
||||
explicit FloatingLiteral(ASTContext &C, EmptyShell Empty)
|
||||
: Expr(FloatingLiteralClass, Empty) {
|
||||
FloatingLiteralBits.IsIEEE =
|
||||
&C.getTargetInfo().getLongDoubleFormat() == &llvm::APFloat::IEEEquad;
|
||||
FloatingLiteralBits.IsExact = false;
|
||||
}
|
||||
explicit FloatingLiteral(ASTContext &C, EmptyShell Empty);
|
||||
|
||||
public:
|
||||
static FloatingLiteral *Create(ASTContext &C, const llvm::APFloat &V,
|
||||
|
|
@ -1381,8 +1393,8 @@ public:
|
|||
return StringRef(StrData.asChar, getByteLength());
|
||||
}
|
||||
|
||||
/// Allow clients that need the byte representation, such as ASTWriterStmt
|
||||
/// ::VisitStringLiteral(), access.
|
||||
/// Allow access to clients that need the byte representation, such as
|
||||
/// ASTWriterStmt::VisitStringLiteral().
|
||||
StringRef getBytes() const {
|
||||
// FIXME: StringRef may not be the right type to use as a result for this.
|
||||
if (CharByteWidth == 1)
|
||||
|
|
@ -1395,6 +1407,8 @@ public:
|
|||
getByteLength());
|
||||
}
|
||||
|
||||
void outputString(raw_ostream &OS);
|
||||
|
||||
uint32_t getCodeUnit(size_t i) const {
|
||||
assert(i < Length && "out of bounds access");
|
||||
if (CharByteWidth == 1)
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
#ifndef LLVM_CLANG_AST_EXPRCXX_H
|
||||
#define LLVM_CLANG_AST_EXPRCXX_H
|
||||
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "clang/AST/UnresolvedSet.h"
|
||||
#include "clang/AST/TemplateBase.h"
|
||||
|
|
@ -50,14 +51,18 @@ class TemplateArgumentListInfo;
|
|||
class CXXOperatorCallExpr : public CallExpr {
|
||||
/// \brief The overloaded operator.
|
||||
OverloadedOperatorKind Operator;
|
||||
SourceRange Range;
|
||||
|
||||
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,
|
||||
operatorloc),
|
||||
Operator(Op) {}
|
||||
Operator(Op) {
|
||||
Range = getSourceRangeImpl();
|
||||
}
|
||||
explicit CXXOperatorCallExpr(ASTContext& C, EmptyShell Empty) :
|
||||
CallExpr(C, CXXOperatorCallExprClass, Empty) { }
|
||||
|
||||
|
|
@ -65,7 +70,6 @@ public:
|
|||
/// getOperator - Returns the kind of overloaded operator that this
|
||||
/// expression refers to.
|
||||
OverloadedOperatorKind getOperator() const { return Operator; }
|
||||
void setOperator(OverloadedOperatorKind Kind) { Operator = Kind; }
|
||||
|
||||
/// getOperatorLoc - Returns the location of the operator symbol in
|
||||
/// the expression. When @c getOperator()==OO_Call, this is the
|
||||
|
|
@ -74,12 +78,15 @@ public:
|
|||
/// bracket.
|
||||
SourceLocation getOperatorLoc() const { return getRParenLoc(); }
|
||||
|
||||
SourceRange getSourceRange() const LLVM_READONLY;
|
||||
SourceRange getSourceRange() const { return Range; }
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CXXOperatorCallExprClass;
|
||||
}
|
||||
static bool classof(const CXXOperatorCallExpr *) { return true; }
|
||||
|
||||
friend class ASTStmtReader;
|
||||
friend class ASTStmtWriter;
|
||||
};
|
||||
|
||||
/// CXXMemberCallExpr - Represents a call to a member function that
|
||||
|
|
@ -112,7 +119,7 @@ public:
|
|||
/// declaration as that of the class context of the CXXMethodDecl which this
|
||||
/// function is calling.
|
||||
/// FIXME: Returns 0 for member pointer call exprs.
|
||||
CXXRecordDecl *getRecordDecl();
|
||||
CXXRecordDecl *getRecordDecl() const;
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CXXMemberCallExprClass;
|
||||
|
|
@ -369,10 +376,21 @@ public:
|
|||
return const_cast<UserDefinedLiteral*>(this)->getCookedLiteral();
|
||||
}
|
||||
|
||||
SourceLocation getLocStart() const {
|
||||
if (getLiteralOperatorKind() == LOK_Template)
|
||||
return getRParenLoc();
|
||||
return getArg(0)->getLocStart();
|
||||
}
|
||||
SourceLocation getLocEnd() const { return getRParenLoc(); }
|
||||
SourceRange getSourceRange() const {
|
||||
return SourceRange(getLocStart(), getLocEnd());
|
||||
}
|
||||
|
||||
|
||||
/// getUDSuffixLoc - Returns the location of a ud-suffix in the expression.
|
||||
/// For a string literal, there may be multiple identical suffixes. This
|
||||
/// returns the first.
|
||||
SourceLocation getUDSuffixLoc() const { return getRParenLoc(); }
|
||||
SourceLocation getUDSuffixLoc() const { return UDSuffixLoc; }
|
||||
|
||||
/// getUDSuffix - Returns the ud-suffix specified for this literal.
|
||||
const IdentifierInfo *getUDSuffix() const;
|
||||
|
|
@ -481,6 +499,10 @@ public:
|
|||
Operand = (TypeSourceInfo*)0;
|
||||
}
|
||||
|
||||
/// Determine whether this typeid has a type operand which is potentially
|
||||
/// evaluated, per C++11 [expr.typeid]p3.
|
||||
bool isPotentiallyEvaluated() const;
|
||||
|
||||
bool isTypeOperand() const { return Operand.is<TypeSourceInfo *>(); }
|
||||
|
||||
/// \brief Retrieves the type operand of this typeid() expression after
|
||||
|
|
@ -859,7 +881,7 @@ public:
|
|||
child_range children() { return child_range(&SubExpr, &SubExpr + 1); }
|
||||
};
|
||||
|
||||
/// CXXConstructExpr - Represents a call to a C++ constructor.
|
||||
/// \brief Represents a call to a C++ constructor.
|
||||
class CXXConstructExpr : public Expr {
|
||||
public:
|
||||
enum ConstructionKind {
|
||||
|
|
@ -983,6 +1005,7 @@ public:
|
|||
|
||||
SourceRange getSourceRange() const LLVM_READONLY;
|
||||
SourceRange getParenRange() const { return ParenRange; }
|
||||
void setParenRange(SourceRange Range) { ParenRange = Range; }
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CXXConstructExprClass ||
|
||||
|
|
@ -998,9 +1021,13 @@ public:
|
|||
friend class ASTStmtReader;
|
||||
};
|
||||
|
||||
/// CXXFunctionalCastExpr - Represents an explicit C++ type conversion
|
||||
/// that uses "functional" notion (C++ [expr.type.conv]). Example: @c
|
||||
/// x = int(0.5);
|
||||
/// \brief Represents an explicit C++ type conversion that uses "functional"
|
||||
/// notation (C++ [expr.type.conv]).
|
||||
///
|
||||
/// Example:
|
||||
/// @code
|
||||
/// x = int(0.5);
|
||||
/// @endcode
|
||||
class CXXFunctionalCastExpr : public ExplicitCastExpr {
|
||||
SourceLocation TyBeginLoc;
|
||||
SourceLocation RParenLoc;
|
||||
|
|
@ -1231,7 +1258,8 @@ private:
|
|||
ArrayRef<Expr *> CaptureInits,
|
||||
ArrayRef<VarDecl *> ArrayIndexVars,
|
||||
ArrayRef<unsigned> ArrayIndexStarts,
|
||||
SourceLocation ClosingBrace);
|
||||
SourceLocation ClosingBrace,
|
||||
bool ContainsUnexpandedParameterPack);
|
||||
|
||||
/// \brief Construct an empty lambda expression.
|
||||
LambdaExpr(EmptyShell Empty, unsigned NumCaptures, bool HasArrayIndexVars)
|
||||
|
|
@ -1269,7 +1297,8 @@ public:
|
|||
ArrayRef<Expr *> CaptureInits,
|
||||
ArrayRef<VarDecl *> ArrayIndexVars,
|
||||
ArrayRef<unsigned> ArrayIndexStarts,
|
||||
SourceLocation ClosingBrace);
|
||||
SourceLocation ClosingBrace,
|
||||
bool ContainsUnexpandedParameterPack);
|
||||
|
||||
/// \brief Construct a new lambda expression that will be deserialized from
|
||||
/// an external source.
|
||||
|
|
@ -1419,15 +1448,16 @@ public:
|
|||
child_range children() { return child_range(); }
|
||||
};
|
||||
|
||||
/// CXXNewExpr - A new expression for memory allocation and constructor calls,
|
||||
/// e.g: "new CXXNewExpr(foo)".
|
||||
/// @brief Represents a new-expression for memory allocation and constructor
|
||||
// calls, e.g: "new CXXNewExpr(foo)".
|
||||
class CXXNewExpr : public Expr {
|
||||
// Contains an optional array size expression, an optional initialization
|
||||
// expression, and any number of optional placement arguments, in that order.
|
||||
Stmt **SubExprs;
|
||||
// Points to the allocation function used.
|
||||
/// \brief Points to the allocation function used.
|
||||
FunctionDecl *OperatorNew;
|
||||
// Points to the deallocation function used in case of error. May be null.
|
||||
/// \brief Points to the deallocation function used in case of error. May be
|
||||
/// null.
|
||||
FunctionDecl *OperatorDelete;
|
||||
|
||||
/// \brief The allocated type-source information, as written in the source.
|
||||
|
|
@ -1607,8 +1637,8 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
/// CXXDeleteExpr - A delete expression for memory deallocation and destructor
|
||||
/// calls, e.g. "delete[] pArray".
|
||||
/// \brief Represents a \c delete expression for memory deallocation and
|
||||
/// destructor calls, e.g. "delete[] pArray".
|
||||
class CXXDeleteExpr : public Expr {
|
||||
// Points to the operator delete overload that is used. Could be a member.
|
||||
FunctionDecl *OperatorDelete;
|
||||
|
|
@ -1678,8 +1708,7 @@ public:
|
|||
friend class ASTStmtReader;
|
||||
};
|
||||
|
||||
/// \brief Structure used to store the type being destroyed by a
|
||||
/// pseudo-destructor expression.
|
||||
/// \brief Stores the type being destroyed by a pseudo-destructor expression.
|
||||
class PseudoDestructorTypeStorage {
|
||||
/// \brief Either the type source information or the name of the type, if
|
||||
/// it couldn't be resolved due to type-dependence.
|
||||
|
|
@ -1866,11 +1895,14 @@ public:
|
|||
child_range children() { return child_range(&Base, &Base + 1); }
|
||||
};
|
||||
|
||||
/// UnaryTypeTraitExpr - A GCC or MS unary type trait, as used in the
|
||||
/// implementation of TR1/C++0x type trait templates.
|
||||
/// \brief Represents a GCC or MS unary type trait, as used in the
|
||||
/// implementation of TR1/C++11 type trait templates.
|
||||
///
|
||||
/// Example:
|
||||
/// __is_pod(int) == true
|
||||
/// __is_enum(std::string) == false
|
||||
/// @code
|
||||
/// __is_pod(int) == true
|
||||
/// __is_enum(std::string) == false
|
||||
/// @endcode
|
||||
class UnaryTypeTraitExpr : public Expr {
|
||||
/// UTT - The trait. A UnaryTypeTrait enum in MSVC compat unsigned.
|
||||
unsigned UTT : 31;
|
||||
|
|
@ -1921,10 +1953,13 @@ public:
|
|||
friend class ASTStmtReader;
|
||||
};
|
||||
|
||||
/// BinaryTypeTraitExpr - A GCC or MS binary type trait, as used in the
|
||||
/// implementation of TR1/C++0x type trait templates.
|
||||
/// \brief Represents a GCC or MS binary type trait, as used in the
|
||||
/// implementation of TR1/C++11 type trait templates.
|
||||
///
|
||||
/// Example:
|
||||
/// __is_base_of(Base, Derived) == true
|
||||
/// @code
|
||||
/// __is_base_of(Base, Derived) == true
|
||||
/// @endcode
|
||||
class BinaryTypeTraitExpr : public Expr {
|
||||
/// BTT - The trait. A BinaryTypeTrait enum in MSVC compat unsigned.
|
||||
unsigned BTT : 8;
|
||||
|
|
@ -2086,30 +2121,33 @@ public:
|
|||
|
||||
};
|
||||
|
||||
/// ArrayTypeTraitExpr - An Embarcadero array type trait, as used in the
|
||||
/// implementation of __array_rank and __array_extent.
|
||||
/// \brief An Embarcadero array type trait, as used in the implementation of
|
||||
/// __array_rank and __array_extent.
|
||||
///
|
||||
/// Example:
|
||||
/// __array_rank(int[10][20]) == 2
|
||||
/// __array_extent(int, 1) == 20
|
||||
/// @code
|
||||
/// __array_rank(int[10][20]) == 2
|
||||
/// __array_extent(int, 1) == 20
|
||||
/// @endcode
|
||||
class ArrayTypeTraitExpr : public Expr {
|
||||
virtual void anchor();
|
||||
|
||||
/// ATT - The trait. An ArrayTypeTrait enum in MSVC compat unsigned.
|
||||
/// \brief The trait. An ArrayTypeTrait enum in MSVC compat unsigned.
|
||||
unsigned ATT : 2;
|
||||
|
||||
/// The value of the type trait. Unspecified if dependent.
|
||||
/// \brief The value of the type trait. Unspecified if dependent.
|
||||
uint64_t Value;
|
||||
|
||||
/// The array dimension being queried, or -1 if not used
|
||||
/// \brief The array dimension being queried, or -1 if not used.
|
||||
Expr *Dimension;
|
||||
|
||||
/// Loc - The location of the type trait keyword.
|
||||
/// \brief The location of the type trait keyword.
|
||||
SourceLocation Loc;
|
||||
|
||||
/// RParen - The location of the closing paren.
|
||||
/// \brief The location of the closing paren.
|
||||
SourceLocation RParen;
|
||||
|
||||
/// The type being queried.
|
||||
/// \brief The type being queried.
|
||||
TypeSourceInfo *QueriedType;
|
||||
|
||||
public:
|
||||
|
|
@ -2156,22 +2194,26 @@ public:
|
|||
friend class ASTStmtReader;
|
||||
};
|
||||
|
||||
/// ExpressionTraitExpr - An expression trait intrinsic
|
||||
/// \brief An expression trait intrinsic.
|
||||
///
|
||||
/// Example:
|
||||
/// __is_lvalue_expr(std::cout) == true
|
||||
/// __is_lvalue_expr(1) == false
|
||||
/// @code
|
||||
/// __is_lvalue_expr(std::cout) == true
|
||||
/// __is_lvalue_expr(1) == false
|
||||
/// @endcode
|
||||
class ExpressionTraitExpr : public Expr {
|
||||
/// ET - The trait. A ExpressionTrait enum in MSVC compat unsigned.
|
||||
/// \brief The trait. A ExpressionTrait enum in MSVC compat unsigned.
|
||||
unsigned ET : 31;
|
||||
/// The value of the type trait. Unspecified if dependent.
|
||||
/// \brief The value of the type trait. Unspecified if dependent.
|
||||
bool Value : 1;
|
||||
|
||||
/// Loc - The location of the type trait keyword.
|
||||
/// \brief The location of the type trait keyword.
|
||||
SourceLocation Loc;
|
||||
|
||||
/// RParen - The location of the closing paren.
|
||||
/// \brief The location of the closing paren.
|
||||
SourceLocation RParen;
|
||||
|
||||
/// \brief The expression being queried.
|
||||
Expr* QueriedExpression;
|
||||
public:
|
||||
ExpressionTraitExpr(SourceLocation loc, ExpressionTrait et,
|
||||
|
|
@ -2190,7 +2232,9 @@ public:
|
|||
: Expr(ExpressionTraitExprClass, Empty), ET(0), Value(false),
|
||||
QueriedExpression() { }
|
||||
|
||||
SourceRange getSourceRange() const LLVM_READONLY { return SourceRange(Loc, RParen);}
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
return SourceRange(Loc, RParen);
|
||||
}
|
||||
|
||||
ExpressionTrait getTrait() const { return static_cast<ExpressionTrait>(ET); }
|
||||
|
||||
|
|
@ -2211,9 +2255,9 @@ public:
|
|||
|
||||
|
||||
/// \brief A reference to an overloaded function set, either an
|
||||
/// \t UnresolvedLookupExpr or an \t UnresolvedMemberExpr.
|
||||
/// \c UnresolvedLookupExpr or an \c UnresolvedMemberExpr.
|
||||
class OverloadExpr : public Expr {
|
||||
/// The common name of these declarations.
|
||||
/// \brief The common name of these declarations.
|
||||
DeclarationNameInfo NameInfo;
|
||||
|
||||
/// \brief The nested-name-specifier that qualifies the name, if any.
|
||||
|
|
@ -2292,7 +2336,7 @@ public:
|
|||
return Result;
|
||||
}
|
||||
|
||||
/// Gets the naming class of this lookup, if any.
|
||||
/// \brief Gets the naming class of this lookup, if any.
|
||||
CXXRecordDecl *getNamingClass() const;
|
||||
|
||||
typedef UnresolvedSetImpl::iterator decls_iterator;
|
||||
|
|
@ -2301,25 +2345,25 @@ public:
|
|||
return UnresolvedSetIterator(Results + NumResults);
|
||||
}
|
||||
|
||||
/// Gets the number of declarations in the unresolved set.
|
||||
/// \brief Gets the number of declarations in the unresolved set.
|
||||
unsigned getNumDecls() const { return NumResults; }
|
||||
|
||||
/// Gets the full name info.
|
||||
/// \brief Gets the full name info.
|
||||
const DeclarationNameInfo &getNameInfo() const { return NameInfo; }
|
||||
|
||||
/// Gets the name looked up.
|
||||
/// \brief Gets the name looked up.
|
||||
DeclarationName getName() const { return NameInfo.getName(); }
|
||||
|
||||
/// Gets the location of the name.
|
||||
/// \brief Gets the location of the name.
|
||||
SourceLocation getNameLoc() const { return NameInfo.getLoc(); }
|
||||
|
||||
/// Fetches the nested-name qualifier, if one was given.
|
||||
/// \brief Fetches the nested-name qualifier, if one was given.
|
||||
NestedNameSpecifier *getQualifier() const {
|
||||
return QualifierLoc.getNestedNameSpecifier();
|
||||
}
|
||||
|
||||
/// Fetches the nested-name qualifier with source-location information, if
|
||||
/// one was given.
|
||||
/// \brief Fetches the nested-name qualifier with source-location
|
||||
/// information, if one was given.
|
||||
NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; }
|
||||
|
||||
/// \brief Retrieve the location of the template keyword preceding
|
||||
|
|
@ -2343,10 +2387,10 @@ public:
|
|||
return getTemplateKWAndArgsInfo()->RAngleLoc;
|
||||
}
|
||||
|
||||
/// Determines whether the name was preceded by the template keyword.
|
||||
/// \brief Determines whether the name was preceded by the template keyword.
|
||||
bool hasTemplateKeyword() const { return getTemplateKeywordLoc().isValid(); }
|
||||
|
||||
/// Determines whether this expression had explicit template arguments.
|
||||
/// \brief Determines whether this expression had explicit template arguments.
|
||||
bool hasExplicitTemplateArgs() const { return getLAngleLoc().isValid(); }
|
||||
|
||||
// Note that, inconsistently with the explicit-template-argument AST
|
||||
|
|
@ -2370,12 +2414,13 @@ public:
|
|||
return getExplicitTemplateArgs().NumTemplateArgs;
|
||||
}
|
||||
|
||||
/// Copies the template arguments into the given structure.
|
||||
/// \brief Copies the template arguments into the given structure.
|
||||
void copyTemplateArgumentsInto(TemplateArgumentListInfo &List) const {
|
||||
getExplicitTemplateArgs().copyInto(List);
|
||||
}
|
||||
|
||||
/// \brief Retrieves the optional explicit template arguments.
|
||||
///
|
||||
/// This points to the same data as getExplicitTemplateArgs(), but
|
||||
/// returns null if there are no explicit template arguments.
|
||||
const ASTTemplateArgumentListInfo *getOptionalExplicitTemplateArgs() {
|
||||
|
|
@ -2394,15 +2439,15 @@ public:
|
|||
};
|
||||
|
||||
/// \brief A reference to a name which we were able to look up during
|
||||
/// parsing but could not resolve to a specific declaration. This
|
||||
/// arises in several ways:
|
||||
/// parsing but could not resolve to a specific declaration.
|
||||
///
|
||||
/// This arises in several ways:
|
||||
/// * we might be waiting for argument-dependent lookup
|
||||
/// * the name might resolve to an overloaded function
|
||||
/// and eventually:
|
||||
/// * the lookup might have included a function template
|
||||
/// These never include UnresolvedUsingValueDecls, which are always
|
||||
/// class members and therefore appear only in
|
||||
/// UnresolvedMemberLookupExprs.
|
||||
/// These never include UnresolvedUsingValueDecls, which are always class
|
||||
/// members and therefore appear only in UnresolvedMemberLookupExprs.
|
||||
class UnresolvedLookupExpr : public OverloadExpr {
|
||||
/// True if these lookup results should be extended by
|
||||
/// argument-dependent lookup if this is the operand of a function
|
||||
|
|
@ -2483,8 +2528,8 @@ public:
|
|||
/// argument-dependent lookup.
|
||||
bool requiresADL() const { return RequiresADL; }
|
||||
|
||||
/// True if namespace ::std should be artificially added to the set of
|
||||
/// associated namespaecs for argument-dependent lookup purposes.
|
||||
/// 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.
|
||||
|
|
@ -2744,9 +2789,9 @@ public:
|
|||
/// type-dependent.
|
||||
///
|
||||
/// The explicit type conversions expressed by
|
||||
/// CXXUnresolvedConstructExpr have the form \c T(a1, a2, ..., aN),
|
||||
/// where \c T is some type and \c a1, a2, ..., aN are values, and
|
||||
/// either \C T is a dependent type or one or more of the \c a's is
|
||||
/// CXXUnresolvedConstructExpr have the form <tt>T(a1, a2, ..., aN)</tt>,
|
||||
/// where \c T is some type and \c a1, \c a2, ..., \c aN are values, and
|
||||
/// either \c T is a dependent type or one or more of the <tt>a</tt>'s is
|
||||
/// type-dependent. For example, this would occur in a template such
|
||||
/// as:
|
||||
///
|
||||
|
|
|
|||
|
|
@ -87,43 +87,45 @@ public:
|
|||
child_range children() { return child_range(); }
|
||||
};
|
||||
|
||||
/// ObjCNumericLiteral - used for objective-c numeric literals;
|
||||
/// as in: @42 or @true (c++/objc++) or @__yes (c/objc)
|
||||
class ObjCNumericLiteral : public Expr {
|
||||
/// Number - expression AST node for the numeric literal
|
||||
Stmt *Number;
|
||||
ObjCMethodDecl *ObjCNumericLiteralMethod;
|
||||
SourceLocation AtLoc;
|
||||
/// ObjCBoxedExpr - used for generalized expression boxing.
|
||||
/// as in: @(strdup("hello world")) or @(random())
|
||||
/// Also used for boxing non-parenthesized numeric literals;
|
||||
/// as in: @42 or \@true (c++/objc++) or \@__yes (c/objc).
|
||||
class ObjCBoxedExpr : public Expr {
|
||||
Stmt *SubExpr;
|
||||
ObjCMethodDecl *BoxingMethod;
|
||||
SourceRange Range;
|
||||
public:
|
||||
ObjCNumericLiteral(Stmt *NL, QualType T, ObjCMethodDecl *method,
|
||||
SourceLocation L)
|
||||
: Expr(ObjCNumericLiteralClass, T, VK_RValue, OK_Ordinary,
|
||||
false, false, false, false), Number(NL),
|
||||
ObjCNumericLiteralMethod(method), AtLoc(L) {}
|
||||
explicit ObjCNumericLiteral(EmptyShell Empty)
|
||||
: Expr(ObjCNumericLiteralClass, Empty) {}
|
||||
ObjCBoxedExpr(Expr *E, QualType T, ObjCMethodDecl *method,
|
||||
SourceRange R)
|
||||
: Expr(ObjCBoxedExprClass, T, VK_RValue, OK_Ordinary,
|
||||
E->isTypeDependent(), E->isValueDependent(),
|
||||
E->isInstantiationDependent(), E->containsUnexpandedParameterPack()),
|
||||
SubExpr(E), BoxingMethod(method), Range(R) {}
|
||||
explicit ObjCBoxedExpr(EmptyShell Empty)
|
||||
: Expr(ObjCBoxedExprClass, Empty) {}
|
||||
|
||||
Expr *getNumber() { return cast<Expr>(Number); }
|
||||
const Expr *getNumber() const { return cast<Expr>(Number); }
|
||||
Expr *getSubExpr() { return cast<Expr>(SubExpr); }
|
||||
const Expr *getSubExpr() const { return cast<Expr>(SubExpr); }
|
||||
|
||||
ObjCMethodDecl *getObjCNumericLiteralMethod() const {
|
||||
return ObjCNumericLiteralMethod;
|
||||
ObjCMethodDecl *getBoxingMethod() const {
|
||||
return BoxingMethod;
|
||||
}
|
||||
|
||||
SourceLocation getAtLoc() const { return AtLoc; }
|
||||
|
||||
SourceLocation getAtLoc() const { return Range.getBegin(); }
|
||||
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
return SourceRange(AtLoc, Number->getSourceRange().getEnd());
|
||||
return Range;
|
||||
}
|
||||
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCNumericLiteralClass;
|
||||
return T->getStmtClass() == ObjCBoxedExprClass;
|
||||
}
|
||||
static bool classof(const ObjCNumericLiteral *) { return true; }
|
||||
static bool classof(const ObjCBoxedExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
child_range children() { return child_range(&Number, &Number+1); }
|
||||
|
||||
child_range children() { return child_range(&SubExpr, &SubExpr+1); }
|
||||
|
||||
friend class ASTStmtReader;
|
||||
};
|
||||
|
||||
|
|
@ -332,9 +334,9 @@ public:
|
|||
};
|
||||
|
||||
|
||||
/// ObjCEncodeExpr, used for @encode in Objective-C. @encode has the same type
|
||||
/// and behavior as StringLiteral except that the string initializer is obtained
|
||||
/// from ASTContext with the encoding type as an argument.
|
||||
/// ObjCEncodeExpr, used for \@encode in Objective-C. \@encode has the same
|
||||
/// type and behavior as StringLiteral except that the string initializer is
|
||||
/// obtained from ASTContext with the encoding type as an argument.
|
||||
class ObjCEncodeExpr : public Expr {
|
||||
TypeSourceInfo *EncodedType;
|
||||
SourceLocation AtLoc, RParenLoc;
|
||||
|
|
@ -376,7 +378,7 @@ public:
|
|||
child_range children() { return child_range(); }
|
||||
};
|
||||
|
||||
/// ObjCSelectorExpr used for @selector in Objective-C.
|
||||
/// ObjCSelectorExpr used for \@selector in Objective-C.
|
||||
class ObjCSelectorExpr : public Expr {
|
||||
Selector SelName;
|
||||
SourceLocation AtLoc, RParenLoc;
|
||||
|
|
@ -419,19 +421,20 @@ public:
|
|||
/// The return type is "Protocol*".
|
||||
class ObjCProtocolExpr : public Expr {
|
||||
ObjCProtocolDecl *TheProtocol;
|
||||
SourceLocation AtLoc, RParenLoc;
|
||||
SourceLocation AtLoc, ProtoLoc, RParenLoc;
|
||||
public:
|
||||
ObjCProtocolExpr(QualType T, ObjCProtocolDecl *protocol,
|
||||
SourceLocation at, SourceLocation rp)
|
||||
SourceLocation at, SourceLocation protoLoc, SourceLocation rp)
|
||||
: Expr(ObjCProtocolExprClass, T, VK_RValue, OK_Ordinary, false, false,
|
||||
false, false),
|
||||
TheProtocol(protocol), AtLoc(at), RParenLoc(rp) {}
|
||||
TheProtocol(protocol), AtLoc(at), ProtoLoc(protoLoc), RParenLoc(rp) {}
|
||||
explicit ObjCProtocolExpr(EmptyShell Empty)
|
||||
: Expr(ObjCProtocolExprClass, Empty) {}
|
||||
|
||||
ObjCProtocolDecl *getProtocol() const { return TheProtocol; }
|
||||
void setProtocol(ObjCProtocolDecl *P) { TheProtocol = P; }
|
||||
|
||||
SourceLocation getProtocolIdLoc() const { return ProtoLoc; }
|
||||
SourceLocation getAtLoc() const { return AtLoc; }
|
||||
SourceLocation getRParenLoc() const { return RParenLoc; }
|
||||
void setAtLoc(SourceLocation L) { AtLoc = L; }
|
||||
|
|
@ -448,6 +451,9 @@ public:
|
|||
|
||||
// Iterators
|
||||
child_range children() { return child_range(); }
|
||||
|
||||
friend class ASTStmtReader;
|
||||
friend class ASTStmtWriter;
|
||||
};
|
||||
|
||||
/// ObjCIvarRefExpr - A reference to an ObjC instance variable.
|
||||
|
|
@ -1019,7 +1025,7 @@ public:
|
|||
/// a l-value or r-value reference will be an l-value or x-value,
|
||||
/// respectively.
|
||||
///
|
||||
/// \param LBrac The location of the open square bracket '['.
|
||||
/// \param LBracLoc The location of the open square bracket '['.
|
||||
///
|
||||
/// \param SuperLoc The location of the "super" keyword.
|
||||
///
|
||||
|
|
@ -1033,8 +1039,6 @@ public:
|
|||
///
|
||||
/// \param Args The message send arguments.
|
||||
///
|
||||
/// \param NumArgs The number of arguments.
|
||||
///
|
||||
/// \param RBracLoc The location of the closing square bracket ']'.
|
||||
static ObjCMessageExpr *Create(ASTContext &Context, QualType T,
|
||||
ExprValueKind VK,
|
||||
|
|
@ -1059,7 +1063,7 @@ public:
|
|||
/// a l-value or r-value reference will be an l-value or x-value,
|
||||
/// respectively.
|
||||
///
|
||||
/// \param LBrac The location of the open square bracket '['.
|
||||
/// \param LBracLoc The location of the open square bracket '['.
|
||||
///
|
||||
/// \param Receiver The type of the receiver, including
|
||||
/// source-location information.
|
||||
|
|
@ -1071,8 +1075,6 @@ public:
|
|||
///
|
||||
/// \param Args The message send arguments.
|
||||
///
|
||||
/// \param NumArgs The number of arguments.
|
||||
///
|
||||
/// \param RBracLoc The location of the closing square bracket ']'.
|
||||
static ObjCMessageExpr *Create(ASTContext &Context, QualType T,
|
||||
ExprValueKind VK,
|
||||
|
|
@ -1095,7 +1097,7 @@ public:
|
|||
/// a l-value or r-value reference will be an l-value or x-value,
|
||||
/// respectively.
|
||||
///
|
||||
/// \param LBrac The location of the open square bracket '['.
|
||||
/// \param LBracLoc The location of the open square bracket '['.
|
||||
///
|
||||
/// \param Receiver The expression used to produce the object that
|
||||
/// will receive this message.
|
||||
|
|
@ -1107,8 +1109,6 @@ public:
|
|||
///
|
||||
/// \param Args The message send arguments.
|
||||
///
|
||||
/// \param NumArgs The number of arguments.
|
||||
///
|
||||
/// \param RBracLoc The location of the closing square bracket ']'.
|
||||
static ObjCMessageExpr *Create(ASTContext &Context, QualType T,
|
||||
ExprValueKind VK,
|
||||
|
|
|
|||
|
|
@ -179,6 +179,9 @@ public:
|
|||
/// \c ObjCInterfaceDecl::setExternallyCompleted().
|
||||
virtual void CompleteType(ObjCInterfaceDecl *Class) { }
|
||||
|
||||
/// \brief Loads comment ranges.
|
||||
virtual void ReadComments() { }
|
||||
|
||||
/// \brief Notify ExternalASTSource that we started deserialization of
|
||||
/// a decl or type so until FinishedDeserializing is called there may be
|
||||
/// decls that are initializing. Must be paired with FinishedDeserializing.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
CLANG_LEVEL := ../../..
|
||||
TD_SRC_DIR = $(PROJ_SRC_DIR)/../Basic
|
||||
BUILT_SOURCES = Attrs.inc AttrImpl.inc StmtNodes.inc DeclNodes.inc
|
||||
BUILT_SOURCES = Attrs.inc AttrImpl.inc StmtNodes.inc DeclNodes.inc CommentNodes.inc
|
||||
|
||||
TABLEGEN_INC_FILES_COMMON = 1
|
||||
|
||||
|
|
@ -27,3 +27,9 @@ $(ObjDir)/DeclNodes.inc.tmp : $(TD_SRC_DIR)/DeclNodes.td $(CLANG_TBLGEN) \
|
|||
$(ObjDir)/.dir
|
||||
$(Echo) "Building Clang declaration node tables with tblgen"
|
||||
$(Verb) $(ClangTableGen) -gen-clang-decl-nodes -o $(call SYSPATH, $@) $<
|
||||
|
||||
$(ObjDir)/CommentNodes.inc.tmp : $(TD_SRC_DIR)/CommentNodes.td $(CLANG_TBLGEN) \
|
||||
$(ObjDir)/.dir
|
||||
$(Echo) "Building Clang comment node tables with tblgen"
|
||||
$(Verb) $(ClangTableGen) -gen-clang-comment-nodes -o $(call SYSPATH, $@) $<
|
||||
|
||||
|
|
|
|||
|
|
@ -121,6 +121,7 @@ public:
|
|||
raw_ostream &) = 0;
|
||||
|
||||
void mangleGlobalBlock(const BlockDecl *BD,
|
||||
const NamedDecl *ID,
|
||||
raw_ostream &Out);
|
||||
void mangleCtorBlock(const CXXConstructorDecl *CD, CXXCtorType CT,
|
||||
const BlockDecl *BD, raw_ostream &Out);
|
||||
|
|
@ -129,7 +130,8 @@ public:
|
|||
void mangleBlock(const DeclContext *DC, const BlockDecl *BD,
|
||||
raw_ostream &Out);
|
||||
// Do the right thing.
|
||||
void mangleBlock(const BlockDecl *BD, raw_ostream &Out);
|
||||
void mangleBlock(const BlockDecl *BD, raw_ostream &Out,
|
||||
const NamedDecl *ID=0);
|
||||
|
||||
void mangleObjCMethodName(const ObjCMethodDecl *MD,
|
||||
raw_ostream &);
|
||||
|
|
|
|||
|
|
@ -11,11 +11,13 @@
|
|||
#define LLVM_CLANG_AST_NSAPI_H
|
||||
|
||||
#include "clang/Basic/IdentifierTable.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
|
||||
namespace clang {
|
||||
class ASTContext;
|
||||
class QualType;
|
||||
class Expr;
|
||||
|
||||
// \brief Provides info and caches identifiers/selectors for NSFoundation API.
|
||||
class NSAPI {
|
||||
|
|
@ -37,15 +39,33 @@ public:
|
|||
|
||||
enum NSStringMethodKind {
|
||||
NSStr_stringWithString,
|
||||
NSStr_stringWithUTF8String,
|
||||
NSStr_stringWithCStringEncoding,
|
||||
NSStr_stringWithCString,
|
||||
NSStr_initWithString
|
||||
};
|
||||
static const unsigned NumNSStringMethods = 2;
|
||||
static const unsigned NumNSStringMethods = 5;
|
||||
|
||||
IdentifierInfo *getNSClassId(NSClassIdKindKind K) const;
|
||||
|
||||
/// \brief The Objective-C NSString selectors.
|
||||
Selector getNSStringSelector(NSStringMethodKind MK) const;
|
||||
|
||||
/// \brief Return NSStringMethodKind if \param Sel is such a selector.
|
||||
llvm::Optional<NSStringMethodKind> getNSStringMethodKind(Selector Sel) const;
|
||||
|
||||
/// \brief Returns true if the expression \param E is a reference of
|
||||
/// "NSUTF8StringEncoding" enum constant.
|
||||
bool isNSUTF8StringEncodingConstant(const Expr *E) const {
|
||||
return isObjCEnumerator(E, "NSUTF8StringEncoding", NSUTF8StringEncodingId);
|
||||
}
|
||||
|
||||
/// \brief Returns true if the expression \param E is a reference of
|
||||
/// "NSASCIIStringEncoding" enum constant.
|
||||
bool isNSASCIIStringEncodingConstant(const Expr *E) const {
|
||||
return isObjCEnumerator(E, "NSASCIIStringEncoding",NSASCIIStringEncodingId);
|
||||
}
|
||||
|
||||
/// \brief Enumerates the NSArray methods used to generate literals.
|
||||
enum NSArrayMethodKind {
|
||||
NSArr_array,
|
||||
|
|
@ -88,6 +108,35 @@ public:
|
|||
llvm::Optional<NSDictionaryMethodKind>
|
||||
getNSDictionaryMethodKind(Selector Sel);
|
||||
|
||||
/// \brief Returns selector for "objectForKeyedSubscript:".
|
||||
Selector getObjectForKeyedSubscriptSelector() const {
|
||||
return getOrInitSelector(StringRef("objectForKeyedSubscript"),
|
||||
objectForKeyedSubscriptSel);
|
||||
}
|
||||
|
||||
/// \brief Returns selector for "objectAtIndexedSubscript:".
|
||||
Selector getObjectAtIndexedSubscriptSelector() const {
|
||||
return getOrInitSelector(StringRef("objectAtIndexedSubscript"),
|
||||
objectAtIndexedSubscriptSel);
|
||||
}
|
||||
|
||||
/// \brief Returns selector for "setObject:forKeyedSubscript".
|
||||
Selector getSetObjectForKeyedSubscriptSelector() const {
|
||||
StringRef Ids[] = { "setObject", "forKeyedSubscript" };
|
||||
return getOrInitSelector(Ids, setObjectForKeyedSubscriptSel);
|
||||
}
|
||||
|
||||
/// \brief Returns selector for "setObject:atIndexedSubscript".
|
||||
Selector getSetObjectAtIndexedSubscriptSelector() const {
|
||||
StringRef Ids[] = { "setObject", "atIndexedSubscript" };
|
||||
return getOrInitSelector(Ids, setObjectAtIndexedSubscriptSel);
|
||||
}
|
||||
|
||||
/// \brief Returns selector for "isEqual:".
|
||||
Selector getIsEqualSelector() const {
|
||||
return getOrInitSelector(StringRef("isEqual"), isEqualSel);
|
||||
}
|
||||
|
||||
/// \brief Enumerates the NSNumber methods used to generate literals.
|
||||
enum NSNumberLiteralMethodKind {
|
||||
NSNumberWithChar,
|
||||
|
|
@ -126,10 +175,22 @@ public:
|
|||
|
||||
/// \brief Determine the appropriate NSNumber factory method kind for a
|
||||
/// literal of the given type.
|
||||
static llvm::Optional<NSNumberLiteralMethodKind>
|
||||
getNSNumberFactoryMethodKind(QualType T);
|
||||
llvm::Optional<NSNumberLiteralMethodKind>
|
||||
getNSNumberFactoryMethodKind(QualType T) const;
|
||||
|
||||
/// \brief Returns true if \param T is a typedef of "BOOL" in objective-c.
|
||||
bool isObjCBOOLType(QualType T) const;
|
||||
/// \brief Returns true if \param T is a typedef of "NSInteger" in objective-c.
|
||||
bool isObjCNSIntegerType(QualType T) const;
|
||||
/// \brief Returns true if \param T is a typedef of "NSUInteger" in objective-c.
|
||||
bool isObjCNSUIntegerType(QualType T) const;
|
||||
|
||||
private:
|
||||
bool isObjCTypedef(QualType T, StringRef name, IdentifierInfo *&II) const;
|
||||
bool isObjCEnumerator(const Expr *E,
|
||||
StringRef name, IdentifierInfo *&II) const;
|
||||
Selector getOrInitSelector(ArrayRef<StringRef> Ids, Selector &Sel) const;
|
||||
|
||||
ASTContext &Ctx;
|
||||
|
||||
mutable IdentifierInfo *ClassIds[NumClassIds];
|
||||
|
|
@ -145,6 +206,13 @@ private:
|
|||
/// \brief The Objective-C NSNumber selectors used to create NSNumber literals.
|
||||
mutable Selector NSNumberClassSelectors[NumNSNumberLiteralMethods];
|
||||
mutable Selector NSNumberInstanceSelectors[NumNSNumberLiteralMethods];
|
||||
|
||||
mutable Selector objectForKeyedSubscriptSel, objectAtIndexedSubscriptSel,
|
||||
setObjectForKeyedSubscriptSel,setObjectAtIndexedSubscriptSel,
|
||||
isEqualSel;
|
||||
|
||||
mutable IdentifierInfo *BOOLId, *NSIntegerId, *NSUIntegerId;
|
||||
mutable IdentifierInfo *NSASCIIStringEncodingId, *NSUTF8StringEncodingId;
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ class TypeLoc;
|
|||
class LangOptions;
|
||||
|
||||
/// \brief Represents a C++ nested name specifier, such as
|
||||
/// "::std::vector<int>::".
|
||||
/// "\::std::vector<int>::".
|
||||
///
|
||||
/// C++ nested name specifiers are the prefixes to qualified
|
||||
/// namespaces. For example, "foo::" in "foo::x" is a nested name
|
||||
|
|
@ -190,7 +190,7 @@ public:
|
|||
bool isInstantiationDependent() const;
|
||||
|
||||
/// \brief Whether this nested-name-specifier contains an unexpanded
|
||||
/// parameter pack (for C++0x variadic templates).
|
||||
/// parameter pack (for C++11 variadic templates).
|
||||
bool containsUnexpandedParameterPack() const;
|
||||
|
||||
/// \brief Print this nested name specifier to the given output
|
||||
|
|
@ -247,7 +247,7 @@ public:
|
|||
/// nested-name-specifier.
|
||||
///
|
||||
/// For example, if this instance refers to a nested-name-specifier
|
||||
/// \c ::std::vector<int>::, the returned source range would cover
|
||||
/// \c \::std::vector<int>::, the returned source range would cover
|
||||
/// from the initial '::' to the last '::'.
|
||||
SourceRange getSourceRange() const LLVM_READONLY;
|
||||
|
||||
|
|
@ -255,7 +255,7 @@ public:
|
|||
/// this nested-name-specifier, not including the prefix.
|
||||
///
|
||||
/// For example, if this instance refers to a nested-name-specifier
|
||||
/// \c ::std::vector<int>::, the returned source range would cover
|
||||
/// \c \::std::vector<int>::, the returned source range would cover
|
||||
/// from "vector" to the last '::'.
|
||||
SourceRange getLocalSourceRange() const;
|
||||
|
||||
|
|
@ -286,7 +286,7 @@ public:
|
|||
/// \brief Return the prefix of this nested-name-specifier.
|
||||
///
|
||||
/// For example, if this instance refers to a nested-name-specifier
|
||||
/// \c ::std::vector<int>::, the prefix is \c ::std::. Note that the
|
||||
/// \c \::std::vector<int>::, the prefix is \c \::std::. Note that the
|
||||
/// returned prefix may be empty, if this is the first component of
|
||||
/// the nested-name-specifier.
|
||||
NestedNameSpecifierLoc getPrefix() const {
|
||||
|
|
@ -443,8 +443,9 @@ public:
|
|||
NestedNameSpecifierLoc getWithLocInContext(ASTContext &Context) const;
|
||||
|
||||
/// \brief Retrieve a nested-name-specifier with location
|
||||
/// information based on the information in this builder. This loc
|
||||
/// will contain references to the builder's internal data and may
|
||||
/// information based on the information in this builder.
|
||||
///
|
||||
/// This loc will contain references to the builder's internal data and may
|
||||
/// be invalidated by any change to the builder.
|
||||
NestedNameSpecifierLoc getTemporary() const {
|
||||
return NestedNameSpecifierLoc(Representation, Buffer);
|
||||
|
|
|
|||
|
|
@ -291,7 +291,7 @@ enum CastKind {
|
|||
CK_CopyAndAutoreleaseBlockObject
|
||||
};
|
||||
|
||||
#define CK_Invalid ((CastKind) -1)
|
||||
static const CastKind CK_Invalid = static_cast<CastKind>(-1);
|
||||
|
||||
enum BinaryOperatorKind {
|
||||
// Operators listed in order of precedence.
|
||||
|
|
|
|||
220
include/clang/AST/RawCommentList.h
Normal file
220
include/clang/AST/RawCommentList.h
Normal file
|
|
@ -0,0 +1,220 @@
|
|||
//===--- RawCommentList.h - Classes for processing raw comments -*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_RAW_COMMENT_LIST_H
|
||||
#define LLVM_CLANG_AST_RAW_COMMENT_LIST_H
|
||||
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
class ASTContext;
|
||||
class ASTReader;
|
||||
class Decl;
|
||||
|
||||
namespace comments {
|
||||
class FullComment;
|
||||
} // end namespace comments
|
||||
|
||||
class RawComment {
|
||||
public:
|
||||
enum CommentKind {
|
||||
RCK_Invalid, ///< Invalid comment
|
||||
RCK_OrdinaryBCPL, ///< Any normal BCPL comments
|
||||
RCK_OrdinaryC, ///< Any normal C comment
|
||||
RCK_BCPLSlash, ///< \code /// stuff \endcode
|
||||
RCK_BCPLExcl, ///< \code //! stuff \endcode
|
||||
RCK_JavaDoc, ///< \code /** stuff */ \endcode
|
||||
RCK_Qt, ///< \code /*! stuff */ \endcode, also used by HeaderDoc
|
||||
RCK_Merged ///< Two or more documentation comments merged together
|
||||
};
|
||||
|
||||
RawComment() : Kind(RCK_Invalid), IsAlmostTrailingComment(false) { }
|
||||
|
||||
RawComment(const SourceManager &SourceMgr, SourceRange SR,
|
||||
bool Merged = false);
|
||||
|
||||
CommentKind getKind() const LLVM_READONLY {
|
||||
return (CommentKind) Kind;
|
||||
}
|
||||
|
||||
bool isInvalid() const LLVM_READONLY {
|
||||
return Kind == RCK_Invalid;
|
||||
}
|
||||
|
||||
bool isMerged() const LLVM_READONLY {
|
||||
return Kind == RCK_Merged;
|
||||
}
|
||||
|
||||
/// Is this comment attached to any declaration?
|
||||
bool isAttached() const LLVM_READONLY {
|
||||
return !DeclOrParsedComment.isNull();
|
||||
}
|
||||
|
||||
/// Return the declaration that this comment is attached to.
|
||||
const Decl *getDecl() const;
|
||||
|
||||
/// Set the declaration that this comment is attached to.
|
||||
void setDecl(const Decl *D) {
|
||||
assert(DeclOrParsedComment.isNull());
|
||||
DeclOrParsedComment = D;
|
||||
}
|
||||
|
||||
/// Returns true if it is a comment that should be put after a member:
|
||||
/// \code ///< stuff \endcode
|
||||
/// \code //!< stuff \endcode
|
||||
/// \code /**< stuff */ \endcode
|
||||
/// \code /*!< stuff */ \endcode
|
||||
bool isTrailingComment() const LLVM_READONLY {
|
||||
assert(isDocumentation());
|
||||
return IsTrailingComment;
|
||||
}
|
||||
|
||||
/// Returns true if it is a probable typo:
|
||||
/// \code //< stuff \endcode
|
||||
/// \code /*< stuff */ \endcode
|
||||
bool isAlmostTrailingComment() const LLVM_READONLY {
|
||||
return IsAlmostTrailingComment;
|
||||
}
|
||||
|
||||
/// Returns true if this comment is not a documentation comment.
|
||||
bool isOrdinary() const LLVM_READONLY {
|
||||
return (Kind == RCK_OrdinaryBCPL) || (Kind == RCK_OrdinaryC);
|
||||
}
|
||||
|
||||
/// Returns true if this comment any kind of a documentation comment.
|
||||
bool isDocumentation() const LLVM_READONLY {
|
||||
return !isInvalid() && !isOrdinary();
|
||||
}
|
||||
|
||||
/// Returns raw comment text with comment markers.
|
||||
StringRef getRawText(const SourceManager &SourceMgr) const {
|
||||
if (RawTextValid)
|
||||
return RawText;
|
||||
|
||||
RawText = getRawTextSlow(SourceMgr);
|
||||
RawTextValid = true;
|
||||
return RawText;
|
||||
}
|
||||
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
return Range;
|
||||
}
|
||||
|
||||
unsigned getBeginLine(const SourceManager &SM) const;
|
||||
unsigned getEndLine(const SourceManager &SM) const;
|
||||
|
||||
const char *getBriefText(const ASTContext &Context) const {
|
||||
if (BriefTextValid)
|
||||
return BriefText;
|
||||
|
||||
return extractBriefText(Context);
|
||||
}
|
||||
|
||||
/// Returns a \c FullComment AST node, parsing the comment if needed.
|
||||
comments::FullComment *getParsed(const ASTContext &Context) const {
|
||||
if (comments::FullComment *FC =
|
||||
DeclOrParsedComment.dyn_cast<comments::FullComment *>())
|
||||
return FC;
|
||||
|
||||
return parse(Context);
|
||||
}
|
||||
|
||||
private:
|
||||
SourceRange Range;
|
||||
|
||||
mutable StringRef RawText;
|
||||
mutable const char *BriefText;
|
||||
mutable llvm::PointerUnion<const Decl *, comments::FullComment *>
|
||||
DeclOrParsedComment;
|
||||
|
||||
mutable bool RawTextValid : 1; ///< True if RawText is valid
|
||||
mutable bool BriefTextValid : 1; ///< True if BriefText is valid
|
||||
|
||||
unsigned Kind : 3;
|
||||
|
||||
bool IsTrailingComment : 1;
|
||||
bool IsAlmostTrailingComment : 1;
|
||||
|
||||
mutable bool BeginLineValid : 1; ///< True if BeginLine is valid
|
||||
mutable bool EndLineValid : 1; ///< True if EndLine is valid
|
||||
mutable unsigned BeginLine; ///< Cached line number
|
||||
mutable unsigned EndLine; ///< Cached line number
|
||||
|
||||
/// \brief Constructor for AST deserialization.
|
||||
RawComment(SourceRange SR, CommentKind K, bool IsTrailingComment,
|
||||
bool IsAlmostTrailingComment) :
|
||||
Range(SR), RawTextValid(false), BriefTextValid(false), Kind(K),
|
||||
IsTrailingComment(IsTrailingComment),
|
||||
IsAlmostTrailingComment(IsAlmostTrailingComment),
|
||||
BeginLineValid(false), EndLineValid(false)
|
||||
{ }
|
||||
|
||||
StringRef getRawTextSlow(const SourceManager &SourceMgr) const;
|
||||
|
||||
const char *extractBriefText(const ASTContext &Context) const;
|
||||
|
||||
comments::FullComment *parse(const ASTContext &Context) const;
|
||||
|
||||
friend class ASTReader;
|
||||
};
|
||||
|
||||
/// \brief Compare comments' source locations.
|
||||
template<>
|
||||
class BeforeThanCompare<RawComment> {
|
||||
const SourceManager &SM;
|
||||
|
||||
public:
|
||||
explicit BeforeThanCompare(const SourceManager &SM) : SM(SM) { }
|
||||
|
||||
bool operator()(const RawComment &LHS, const RawComment &RHS) {
|
||||
return SM.isBeforeInTranslationUnit(LHS.getSourceRange().getBegin(),
|
||||
RHS.getSourceRange().getBegin());
|
||||
}
|
||||
|
||||
bool operator()(const RawComment *LHS, const RawComment *RHS) {
|
||||
return operator()(*LHS, *RHS);
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief This class represents all comments included in the translation unit,
|
||||
/// sorted in order of appearance in the translation unit.
|
||||
class RawCommentList {
|
||||
public:
|
||||
RawCommentList(SourceManager &SourceMgr) :
|
||||
SourceMgr(SourceMgr), OnlyWhitespaceSeen(true) { }
|
||||
|
||||
void addComment(const RawComment &RC, llvm::BumpPtrAllocator &Allocator);
|
||||
|
||||
ArrayRef<RawComment *> getComments() const {
|
||||
return Comments;
|
||||
}
|
||||
|
||||
private:
|
||||
SourceManager &SourceMgr;
|
||||
std::vector<RawComment *> Comments;
|
||||
RawComment LastComment;
|
||||
bool OnlyWhitespaceSeen;
|
||||
|
||||
void addCommentsToFront(const std::vector<RawComment *> &C) {
|
||||
size_t OldSize = Comments.size();
|
||||
Comments.resize(C.size() + OldSize);
|
||||
std::copy_backward(Comments.begin(), Comments.begin() + OldSize,
|
||||
Comments.end());
|
||||
std::copy(C.begin(), C.end(), Comments.begin());
|
||||
}
|
||||
|
||||
friend class ASTReader;
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -14,10 +14,9 @@
|
|||
#ifndef LLVM_CLANG_AST_LAYOUTINFO_H
|
||||
#define LLVM_CLANG_AST_LAYOUTINFO_H
|
||||
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "clang/AST/CharUnits.h"
|
||||
#include "clang/AST/DeclCXX.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
|
||||
namespace clang {
|
||||
class ASTContext;
|
||||
|
|
@ -33,18 +32,43 @@ namespace clang {
|
|||
/// ObjCInterfaceDecl. FIXME - Find appropriate name.
|
||||
/// These objects are managed by ASTContext.
|
||||
class ASTRecordLayout {
|
||||
public:
|
||||
struct VBaseInfo {
|
||||
/// The offset to this virtual base in the complete-object layout
|
||||
/// of this class.
|
||||
CharUnits VBaseOffset;
|
||||
|
||||
private:
|
||||
/// Whether this virtual base requires a vtordisp field in the
|
||||
/// Microsoft ABI. These fields are required for certain operations
|
||||
/// in constructors and destructors.
|
||||
bool HasVtorDisp;
|
||||
|
||||
public:
|
||||
bool hasVtorDisp() const { return HasVtorDisp; }
|
||||
|
||||
VBaseInfo() : HasVtorDisp(false) {}
|
||||
|
||||
VBaseInfo(CharUnits VBaseOffset, bool hasVtorDisp) :
|
||||
VBaseOffset(VBaseOffset), HasVtorDisp(hasVtorDisp) {}
|
||||
};
|
||||
|
||||
typedef llvm::DenseMap<const CXXRecordDecl *, VBaseInfo>
|
||||
VBaseOffsetsMapTy;
|
||||
|
||||
private:
|
||||
/// Size - Size of record in characters.
|
||||
CharUnits Size;
|
||||
|
||||
/// DataSize - Size of record in characters without tail padding.
|
||||
CharUnits DataSize;
|
||||
|
||||
/// FieldOffsets - Array of field offsets in bits.
|
||||
uint64_t *FieldOffsets;
|
||||
|
||||
// Alignment - Alignment of record in characters.
|
||||
CharUnits Alignment;
|
||||
|
||||
/// FieldOffsets - Array of field offsets in bits.
|
||||
uint64_t *FieldOffsets;
|
||||
|
||||
// FieldCount - Number of fields.
|
||||
unsigned FieldCount;
|
||||
|
||||
|
|
@ -63,11 +87,13 @@ class ASTRecordLayout {
|
|||
/// any empty subobjects.
|
||||
CharUnits SizeOfLargestEmptySubobject;
|
||||
|
||||
/// VFPtrOffset - Virtual function table offset (Microsoft-only).
|
||||
CharUnits VFPtrOffset;
|
||||
|
||||
/// VBPtrOffset - Virtual base table offset (Microsoft-only).
|
||||
CharUnits VBPtrOffset;
|
||||
|
||||
/// HasOwnVFPtr - Does this class provide a virtual function table
|
||||
/// (vtable in Itanium, vftbl in Microsoft) that is independent from
|
||||
/// its base classes?
|
||||
bool HasOwnVFPtr; // TODO: stash this somewhere more efficient
|
||||
|
||||
/// PrimaryBase - The primary base info for this record.
|
||||
llvm::PointerIntPair<const CXXRecordDecl *, 1, bool> PrimaryBase;
|
||||
|
|
@ -79,7 +105,7 @@ class ASTRecordLayout {
|
|||
BaseOffsetsMapTy BaseOffsets;
|
||||
|
||||
/// VBaseOffsets - Contains a map from vbase classes to their offset.
|
||||
BaseOffsetsMapTy VBaseOffsets;
|
||||
VBaseOffsetsMapTy VBaseOffsets;
|
||||
};
|
||||
|
||||
/// CXXInfo - If the record layout is for a C++ record, this will have
|
||||
|
|
@ -96,7 +122,7 @@ class ASTRecordLayout {
|
|||
typedef CXXRecordLayoutInfo::BaseOffsetsMapTy BaseOffsetsMapTy;
|
||||
ASTRecordLayout(const ASTContext &Ctx,
|
||||
CharUnits size, CharUnits alignment,
|
||||
CharUnits vfptroffset, CharUnits vbptroffset,
|
||||
bool hasOwnVFPtr, CharUnits vbptroffset,
|
||||
CharUnits datasize,
|
||||
const uint64_t *fieldoffsets, unsigned fieldcount,
|
||||
CharUnits nonvirtualsize, CharUnits nonvirtualalign,
|
||||
|
|
@ -104,7 +130,7 @@ class ASTRecordLayout {
|
|||
const CXXRecordDecl *PrimaryBase,
|
||||
bool IsPrimaryBaseVirtual,
|
||||
const BaseOffsetsMapTy& BaseOffsets,
|
||||
const BaseOffsetsMapTy& VBaseOffsets);
|
||||
const VBaseOffsetsMapTy& VBaseOffsets);
|
||||
|
||||
~ASTRecordLayout() {}
|
||||
|
||||
|
|
@ -180,27 +206,7 @@ public:
|
|||
assert(CXXInfo && "Record layout does not have C++ specific info!");
|
||||
assert(CXXInfo->VBaseOffsets.count(VBase) && "Did not find base!");
|
||||
|
||||
return CXXInfo->VBaseOffsets[VBase];
|
||||
}
|
||||
|
||||
/// getBaseClassOffsetInBits - Get the offset, in bits, for the given
|
||||
/// base class.
|
||||
uint64_t getBaseClassOffsetInBits(const CXXRecordDecl *Base) const {
|
||||
assert(CXXInfo && "Record layout does not have C++ specific info!");
|
||||
assert(CXXInfo->BaseOffsets.count(Base) && "Did not find base!");
|
||||
|
||||
return getBaseClassOffset(Base).getQuantity() *
|
||||
Base->getASTContext().getCharWidth();
|
||||
}
|
||||
|
||||
/// getVBaseClassOffsetInBits - Get the offset, in bits, for the given
|
||||
/// base class.
|
||||
uint64_t getVBaseClassOffsetInBits(const CXXRecordDecl *VBase) const {
|
||||
assert(CXXInfo && "Record layout does not have C++ specific info!");
|
||||
assert(CXXInfo->VBaseOffsets.count(VBase) && "Did not find base!");
|
||||
|
||||
return getVBaseClassOffset(VBase).getQuantity() *
|
||||
VBase->getASTContext().getCharWidth();
|
||||
return CXXInfo->VBaseOffsets[VBase].VBaseOffset;
|
||||
}
|
||||
|
||||
CharUnits getSizeOfLargestEmptySubobject() const {
|
||||
|
|
@ -208,11 +214,16 @@ public:
|
|||
return CXXInfo->SizeOfLargestEmptySubobject;
|
||||
}
|
||||
|
||||
/// getVFPtrOffset - Get the offset for virtual function table pointer.
|
||||
/// This is only meaningful with the Microsoft ABI.
|
||||
CharUnits getVFPtrOffset() const {
|
||||
/// hasOwnVFPtr - Does this class provide its own virtual-function
|
||||
/// table pointer, rather than inheriting one from a primary base
|
||||
/// class? If so, it is at offset zero.
|
||||
///
|
||||
/// This implies that the ABI has no primary base class, meaning
|
||||
/// that it has no base classes that are suitable under the conditions
|
||||
/// of the ABI.
|
||||
bool hasOwnVFPtr() const {
|
||||
assert(CXXInfo && "Record layout does not have C++ specific info!");
|
||||
return CXXInfo->VFPtrOffset;
|
||||
return CXXInfo->HasOwnVFPtr;
|
||||
}
|
||||
|
||||
/// getVBPtrOffset - Get the offset for virtual base table pointer.
|
||||
|
|
@ -221,6 +232,11 @@ public:
|
|||
assert(CXXInfo && "Record layout does not have C++ specific info!");
|
||||
return CXXInfo->VBPtrOffset;
|
||||
}
|
||||
|
||||
const VBaseOffsetsMapTy &getVBaseOffsetsMap() const {
|
||||
assert(CXXInfo && "Record layout does not have C++ specific info!");
|
||||
return CXXInfo->VBaseOffsets;
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
|
|
|||
|
|
@ -148,10 +148,15 @@ public:
|
|||
/// TypeLocs.
|
||||
bool shouldWalkTypesOfTypeLocs() const { return true; }
|
||||
|
||||
/// \brief Return whether this visitor should recurse into implicit
|
||||
/// code, e.g., implicit constructors and destructors.
|
||||
bool shouldVisitImplicitCode() const { return false; }
|
||||
|
||||
/// \brief Return whether \param S should be traversed using data recursion
|
||||
/// to avoid a stack overflow with extreme cases.
|
||||
bool shouldUseDataRecursionFor(Stmt *S) const {
|
||||
return isa<BinaryOperator>(S) || isa<UnaryOperator>(S) || isa<CaseStmt>(S);
|
||||
return isa<BinaryOperator>(S) || isa<UnaryOperator>(S) ||
|
||||
isa<CaseStmt>(S) || isa<CXXOperatorCallExpr>(S);
|
||||
}
|
||||
|
||||
/// \brief Recursively visit a statement or expression, by
|
||||
|
|
@ -392,8 +397,8 @@ public:
|
|||
private:
|
||||
// These are helper methods used by more than one Traverse* method.
|
||||
bool TraverseTemplateParameterListHelper(TemplateParameterList *TPL);
|
||||
bool TraverseClassInstantiations(ClassTemplateDecl* D, Decl *Pattern);
|
||||
bool TraverseFunctionInstantiations(FunctionTemplateDecl* D) ;
|
||||
bool TraverseClassInstantiations(ClassTemplateDecl *D);
|
||||
bool TraverseFunctionInstantiations(FunctionTemplateDecl *D) ;
|
||||
bool TraverseTemplateArgumentLocsHelper(const TemplateArgumentLoc *TAL,
|
||||
unsigned Count);
|
||||
bool TraverseArrayTypeLocHelper(ArrayTypeLoc TL);
|
||||
|
|
@ -404,18 +409,14 @@ private:
|
|||
bool TraverseFunctionHelper(FunctionDecl *D);
|
||||
bool TraverseVarHelper(VarDecl *D);
|
||||
|
||||
bool Walk(Stmt *S);
|
||||
|
||||
struct EnqueueJob {
|
||||
Stmt *S;
|
||||
Stmt::child_iterator StmtIt;
|
||||
|
||||
EnqueueJob(Stmt *S) : S(S), StmtIt() {
|
||||
if (Expr *E = dyn_cast_or_null<Expr>(S))
|
||||
S = E->IgnoreParens();
|
||||
}
|
||||
EnqueueJob(Stmt *S) : S(S), StmtIt() {}
|
||||
};
|
||||
bool dataTraverse(Stmt *S);
|
||||
bool dataTraverseNode(Stmt *S, bool &EnqueueChildren);
|
||||
};
|
||||
|
||||
template<typename Derived>
|
||||
|
|
@ -434,7 +435,12 @@ bool RecursiveASTVisitor<Derived>::dataTraverse(Stmt *S) {
|
|||
|
||||
if (getDerived().shouldUseDataRecursionFor(CurrS)) {
|
||||
if (job.StmtIt == Stmt::child_iterator()) {
|
||||
if (!Walk(CurrS)) return false;
|
||||
bool EnqueueChildren = true;
|
||||
if (!dataTraverseNode(CurrS, EnqueueChildren)) return false;
|
||||
if (!EnqueueChildren) {
|
||||
Queue.pop_back();
|
||||
continue;
|
||||
}
|
||||
job.StmtIt = CurrS->child_begin();
|
||||
} else {
|
||||
++job.StmtIt;
|
||||
|
|
@ -455,10 +461,25 @@ bool RecursiveASTVisitor<Derived>::dataTraverse(Stmt *S) {
|
|||
}
|
||||
|
||||
template<typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::Walk(Stmt *S) {
|
||||
bool RecursiveASTVisitor<Derived>::dataTraverseNode(Stmt *S,
|
||||
bool &EnqueueChildren) {
|
||||
|
||||
// The cast for DISPATCH_WALK is needed for older versions of g++, but causes
|
||||
// problems for MSVC. So we'll skip the cast entirely for MSVC.
|
||||
#if defined(_MSC_VER)
|
||||
#define GCC_CAST(CLASS)
|
||||
#else
|
||||
#define GCC_CAST(CLASS) (bool (RecursiveASTVisitor::*)(CLASS*))
|
||||
#endif
|
||||
|
||||
// Dispatch to the corresponding WalkUpFrom* function only if the derived
|
||||
// class didn't override Traverse* (and thus the traversal is trivial).
|
||||
#define DISPATCH_WALK(NAME, CLASS, VAR) \
|
||||
return getDerived().WalkUpFrom##NAME(static_cast<CLASS*>(VAR));
|
||||
if (&RecursiveASTVisitor::Traverse##NAME == \
|
||||
GCC_CAST(CLASS)&Derived::Traverse##NAME) \
|
||||
return getDerived().WalkUpFrom##NAME(static_cast<CLASS*>(VAR)); \
|
||||
EnqueueChildren = false; \
|
||||
return getDerived().Traverse##NAME(static_cast<CLASS*>(VAR));
|
||||
|
||||
if (BinaryOperator *BinOp = dyn_cast<BinaryOperator>(S)) {
|
||||
switch (BinOp->getOpcode()) {
|
||||
|
|
@ -495,6 +516,7 @@ bool RecursiveASTVisitor<Derived>::Walk(Stmt *S) {
|
|||
}
|
||||
|
||||
#undef DISPATCH_WALK
|
||||
#undef GCC_CAST
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -591,10 +613,9 @@ bool RecursiveASTVisitor<Derived>::TraverseDecl(Decl *D) {
|
|||
if (!D)
|
||||
return true;
|
||||
|
||||
// As a syntax visitor, we want to ignore declarations for
|
||||
// implicitly-defined declarations (ones not typed explicitly by the
|
||||
// user).
|
||||
if (D->isImplicit())
|
||||
// As a syntax visitor, by default we want to ignore declarations for
|
||||
// implicit declarations (ones not typed explicitly by the user).
|
||||
if (!getDerived().shouldVisitImplicitCode() && D->isImplicit())
|
||||
return true;
|
||||
|
||||
switch (D->getKind()) {
|
||||
|
|
@ -1231,7 +1252,8 @@ bool RecursiveASTVisitor<Derived>::Traverse##DECL (DECL *D) { \
|
|||
DEF_TRAVERSE_DECL(AccessSpecDecl, { })
|
||||
|
||||
DEF_TRAVERSE_DECL(BlockDecl, {
|
||||
TRY_TO(TraverseTypeLoc(D->getSignatureAsWritten()->getTypeLoc()));
|
||||
if (TypeSourceInfo *TInfo = D->getSignatureAsWritten())
|
||||
TRY_TO(TraverseTypeLoc(TInfo->getTypeLoc()));
|
||||
TRY_TO(TraverseStmt(D->getBody()));
|
||||
// This return statement makes sure the traversal of nodes in
|
||||
// decls_begin()/decls_end() (done in the DEF_TRAVERSE_DECL macro)
|
||||
|
|
@ -1269,7 +1291,13 @@ DEF_TRAVERSE_DECL(FriendTemplateDecl, {
|
|||
})
|
||||
|
||||
DEF_TRAVERSE_DECL(ClassScopeFunctionSpecializationDecl, {
|
||||
TRY_TO(TraverseDecl(D->getSpecialization()));
|
||||
TRY_TO(TraverseDecl(D->getSpecialization()));
|
||||
|
||||
if (D->hasExplicitTemplateArgs()) {
|
||||
const TemplateArgumentListInfo& args = D->templateArgs();
|
||||
TRY_TO(TraverseTemplateArgumentLocsHelper(
|
||||
args.getArgumentArray(), args.size()));
|
||||
}
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_DECL(LinkageSpecDecl, { })
|
||||
|
|
@ -1377,35 +1405,20 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateParameterListHelper(
|
|||
}
|
||||
|
||||
// A helper method for traversing the implicit instantiations of a
|
||||
// class.
|
||||
// class template.
|
||||
template<typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::TraverseClassInstantiations(
|
||||
ClassTemplateDecl* D, Decl *Pattern) {
|
||||
assert(isa<ClassTemplateDecl>(Pattern) ||
|
||||
isa<ClassTemplatePartialSpecializationDecl>(Pattern));
|
||||
|
||||
ClassTemplateDecl *D) {
|
||||
ClassTemplateDecl::spec_iterator end = D->spec_end();
|
||||
for (ClassTemplateDecl::spec_iterator it = D->spec_begin(); it != end; ++it) {
|
||||
ClassTemplateSpecializationDecl* SD = *it;
|
||||
|
||||
switch (SD->getSpecializationKind()) {
|
||||
// Visit the implicit instantiations with the requested pattern.
|
||||
case TSK_ImplicitInstantiation: {
|
||||
llvm::PointerUnion<ClassTemplateDecl *,
|
||||
ClassTemplatePartialSpecializationDecl *> U
|
||||
= SD->getInstantiatedFrom();
|
||||
|
||||
bool ShouldVisit;
|
||||
if (U.is<ClassTemplateDecl*>())
|
||||
ShouldVisit = (U.get<ClassTemplateDecl*>() == Pattern);
|
||||
else
|
||||
ShouldVisit
|
||||
= (U.get<ClassTemplatePartialSpecializationDecl*>() == Pattern);
|
||||
|
||||
if (ShouldVisit)
|
||||
TRY_TO(TraverseDecl(SD));
|
||||
case TSK_Undeclared:
|
||||
case TSK_ImplicitInstantiation:
|
||||
TRY_TO(TraverseDecl(SD));
|
||||
break;
|
||||
}
|
||||
|
||||
// We don't need to do anything on an explicit instantiation
|
||||
// or explicit specialization because there will be an explicit
|
||||
|
|
@ -1414,11 +1427,6 @@ bool RecursiveASTVisitor<Derived>::TraverseClassInstantiations(
|
|||
case TSK_ExplicitInstantiationDefinition:
|
||||
case TSK_ExplicitSpecialization:
|
||||
break;
|
||||
|
||||
// We don't need to do anything for an uninstantiated
|
||||
// specialization.
|
||||
case TSK_Undeclared:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1433,12 +1441,12 @@ DEF_TRAVERSE_DECL(ClassTemplateDecl, {
|
|||
// By default, we do not traverse the instantiations of
|
||||
// class templates since they do not appear in the user code. The
|
||||
// following code optionally traverses them.
|
||||
if (getDerived().shouldVisitTemplateInstantiations()) {
|
||||
// If this is the definition of the primary template, visit
|
||||
// instantiations which were formed from this pattern.
|
||||
if (D->isThisDeclarationADefinition())
|
||||
TRY_TO(TraverseClassInstantiations(D, D));
|
||||
}
|
||||
//
|
||||
// We only traverse the class instantiations when we see the canonical
|
||||
// declaration of the template, to ensure we only visit them once.
|
||||
if (getDerived().shouldVisitTemplateInstantiations() &&
|
||||
D == D->getCanonicalDecl())
|
||||
TRY_TO(TraverseClassInstantiations(D));
|
||||
|
||||
// Note that getInstantiatedFromMemberTemplate() is just a link
|
||||
// from a template instantiation back to the template from which
|
||||
|
|
@ -1449,24 +1457,25 @@ DEF_TRAVERSE_DECL(ClassTemplateDecl, {
|
|||
// function while skipping its specializations.
|
||||
template<typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::TraverseFunctionInstantiations(
|
||||
FunctionTemplateDecl* D) {
|
||||
FunctionTemplateDecl *D) {
|
||||
FunctionTemplateDecl::spec_iterator end = D->spec_end();
|
||||
for (FunctionTemplateDecl::spec_iterator it = D->spec_begin(); it != end;
|
||||
++it) {
|
||||
FunctionDecl* FD = *it;
|
||||
switch (FD->getTemplateSpecializationKind()) {
|
||||
case TSK_Undeclared:
|
||||
case TSK_ImplicitInstantiation:
|
||||
// We don't know what kind of FunctionDecl this is.
|
||||
TRY_TO(TraverseDecl(FD));
|
||||
break;
|
||||
|
||||
// No need to visit explicit instantiations, we'll find the node
|
||||
// eventually.
|
||||
// FIXME: For now traverse explicit instantiations here. Change that
|
||||
// once they are represented as dedicated nodes in the AST.
|
||||
case TSK_ExplicitInstantiationDeclaration:
|
||||
case TSK_ExplicitInstantiationDefinition:
|
||||
TRY_TO(TraverseDecl(FD));
|
||||
break;
|
||||
|
||||
case TSK_Undeclared: // Declaration of the template definition.
|
||||
case TSK_ExplicitSpecialization:
|
||||
break;
|
||||
}
|
||||
|
|
@ -1480,26 +1489,21 @@ DEF_TRAVERSE_DECL(FunctionTemplateDecl, {
|
|||
TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters()));
|
||||
|
||||
// By default, we do not traverse the instantiations of
|
||||
// function templates since they do not apprear in the user code. The
|
||||
// function templates since they do not appear in the user code. The
|
||||
// following code optionally traverses them.
|
||||
if (getDerived().shouldVisitTemplateInstantiations()) {
|
||||
// Explicit function specializations will be traversed from the
|
||||
// context of their declaration. There is therefore no need to
|
||||
// traverse them for here.
|
||||
//
|
||||
// In addition, we only traverse the function instantiations when
|
||||
// the function template is a function template definition.
|
||||
if (D->isThisDeclarationADefinition()) {
|
||||
TRY_TO(TraverseFunctionInstantiations(D));
|
||||
}
|
||||
}
|
||||
//
|
||||
// We only traverse the function instantiations when we see the canonical
|
||||
// declaration of the template, to ensure we only visit them once.
|
||||
if (getDerived().shouldVisitTemplateInstantiations() &&
|
||||
D == D->getCanonicalDecl())
|
||||
TRY_TO(TraverseFunctionInstantiations(D));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_DECL(TemplateTemplateParmDecl, {
|
||||
// D is the "T" in something like
|
||||
// template <template <typename> class T> class container { };
|
||||
TRY_TO(TraverseDecl(D->getTemplatedDecl()));
|
||||
if (D->hasDefaultArgument()) {
|
||||
if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) {
|
||||
TRY_TO(TraverseTemplateArgumentLoc(D->getDefaultArgument()));
|
||||
}
|
||||
TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters()));
|
||||
|
|
@ -1509,7 +1513,7 @@ DEF_TRAVERSE_DECL(TemplateTypeParmDecl, {
|
|||
// D is the "T" in something like "template<typename T> class vector;"
|
||||
if (D->getTypeForDecl())
|
||||
TRY_TO(TraverseType(QualType(D->getTypeForDecl(), 0)));
|
||||
if (D->hasDefaultArgument())
|
||||
if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited())
|
||||
TRY_TO(TraverseTypeLoc(D->getDefaultArgumentInfo()->getTypeLoc()));
|
||||
})
|
||||
|
||||
|
|
@ -1567,7 +1571,7 @@ bool RecursiveASTVisitor<Derived>::TraverseCXXRecordHelper(
|
|||
CXXRecordDecl *D) {
|
||||
if (!TraverseRecordHelper(D))
|
||||
return false;
|
||||
if (D->hasDefinition()) {
|
||||
if (D->isCompleteDefinition()) {
|
||||
for (CXXRecordDecl::base_class_iterator I = D->bases_begin(),
|
||||
E = D->bases_end();
|
||||
I != E; ++I) {
|
||||
|
|
@ -1634,11 +1638,7 @@ DEF_TRAVERSE_DECL(ClassTemplatePartialSpecializationDecl, {
|
|||
// template args here.
|
||||
TRY_TO(TraverseCXXRecordHelper(D));
|
||||
|
||||
// If we're visiting instantiations, visit the instantiations of
|
||||
// this template now.
|
||||
if (getDerived().shouldVisitTemplateInstantiations() &&
|
||||
D->isThisDeclarationADefinition())
|
||||
TRY_TO(TraverseClassInstantiations(D->getSpecializedTemplate(), D));
|
||||
// Instantiations will have been visited with the primary template.
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_DECL(EnumConstantDecl, {
|
||||
|
|
@ -1714,7 +1714,9 @@ bool RecursiveASTVisitor<Derived>::TraverseFunctionHelper(FunctionDecl *D) {
|
|||
// FunctionNoProtoType or FunctionProtoType, or a typedef. This
|
||||
// also covers the return type and the function parameters,
|
||||
// including exception specifications.
|
||||
TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc()));
|
||||
if (clang::TypeSourceInfo *TSI = D->getTypeSourceInfo()) {
|
||||
TRY_TO(TraverseTypeLoc(TSI->getTypeLoc()));
|
||||
}
|
||||
|
||||
if (CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(D)) {
|
||||
// Constructor initializers.
|
||||
|
|
@ -1767,7 +1769,8 @@ template<typename Derived>
|
|||
bool RecursiveASTVisitor<Derived>::TraverseVarHelper(VarDecl *D) {
|
||||
TRY_TO(TraverseDeclaratorHelper(D));
|
||||
// Default params are taken care of when we traverse the ParmVarDecl.
|
||||
if (!isa<ParmVarDecl>(D))
|
||||
if (!isa<ParmVarDecl>(D) &&
|
||||
(!D->isCXXForRangeDecl() || getDerived().shouldVisitImplicitCode()))
|
||||
TRY_TO(TraverseStmt(D->getInit()));
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1783,7 +1786,8 @@ DEF_TRAVERSE_DECL(ImplicitParamDecl, {
|
|||
DEF_TRAVERSE_DECL(NonTypeTemplateParmDecl, {
|
||||
// A non-type template parameter, e.g. "S" in template<int S> class Foo ...
|
||||
TRY_TO(TraverseDeclaratorHelper(D));
|
||||
TRY_TO(TraverseStmt(D->getDefaultArgument()));
|
||||
if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited())
|
||||
TRY_TO(TraverseStmt(D->getDefaultArgument()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_DECL(ParmVarDecl, {
|
||||
|
|
@ -1837,6 +1841,11 @@ DEF_TRAVERSE_STMT(AsmStmt, {
|
|||
// children() iterates over inputExpr and outputExpr.
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_STMT(MSAsmStmt, {
|
||||
// FIXME: MS Asm doesn't currently parse Constraints, Clobbers, etc. Once
|
||||
// added this needs to be implemented.
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_STMT(CXXCatchStmt, {
|
||||
TRY_TO(TraverseDecl(S->getExceptionDecl()));
|
||||
// children() iterates over the handler block.
|
||||
|
|
@ -1879,7 +1888,15 @@ DEF_TRAVERSE_STMT(ObjCAtThrowStmt, { })
|
|||
DEF_TRAVERSE_STMT(ObjCAtTryStmt, { })
|
||||
DEF_TRAVERSE_STMT(ObjCForCollectionStmt, { })
|
||||
DEF_TRAVERSE_STMT(ObjCAutoreleasePoolStmt, { })
|
||||
DEF_TRAVERSE_STMT(CXXForRangeStmt, { })
|
||||
DEF_TRAVERSE_STMT(CXXForRangeStmt, {
|
||||
if (!getDerived().shouldVisitImplicitCode()) {
|
||||
TRY_TO(TraverseStmt(S->getLoopVarStmt()));
|
||||
TRY_TO(TraverseStmt(S->getRangeInit()));
|
||||
TRY_TO(TraverseStmt(S->getBody()));
|
||||
// Visit everything else only if shouldVisitImplicitCode().
|
||||
return true;
|
||||
}
|
||||
})
|
||||
DEF_TRAVERSE_STMT(MSDependentExistsStmt, {
|
||||
TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
|
||||
TRY_TO(TraverseDeclarationNameInfo(S->getNameInfo()));
|
||||
|
|
@ -2146,7 +2163,10 @@ DEF_TRAVERSE_STMT(ExtVectorElementExpr, { })
|
|||
DEF_TRAVERSE_STMT(GNUNullExpr, { })
|
||||
DEF_TRAVERSE_STMT(ImplicitValueInitExpr, { })
|
||||
DEF_TRAVERSE_STMT(ObjCBoolLiteralExpr, { })
|
||||
DEF_TRAVERSE_STMT(ObjCEncodeExpr, { })
|
||||
DEF_TRAVERSE_STMT(ObjCEncodeExpr, {
|
||||
if (TypeSourceInfo *TInfo = S->getEncodedTypeSourceInfo())
|
||||
TRY_TO(TraverseTypeLoc(TInfo->getTypeLoc()));
|
||||
})
|
||||
DEF_TRAVERSE_STMT(ObjCIsaExpr, { })
|
||||
DEF_TRAVERSE_STMT(ObjCIvarRefExpr, { })
|
||||
DEF_TRAVERSE_STMT(ObjCMessageExpr, { })
|
||||
|
|
@ -2209,7 +2229,7 @@ DEF_TRAVERSE_STMT(FloatingLiteral, { })
|
|||
DEF_TRAVERSE_STMT(ImaginaryLiteral, { })
|
||||
DEF_TRAVERSE_STMT(StringLiteral, { })
|
||||
DEF_TRAVERSE_STMT(ObjCStringLiteral, { })
|
||||
DEF_TRAVERSE_STMT(ObjCNumericLiteral, { })
|
||||
DEF_TRAVERSE_STMT(ObjCBoxedExpr, { })
|
||||
DEF_TRAVERSE_STMT(ObjCArrayLiteral, { })
|
||||
DEF_TRAVERSE_STMT(ObjCDictionaryLiteral, { })
|
||||
|
||||
|
|
|
|||
|
|
@ -25,26 +25,25 @@ template<typename decl_type>
|
|||
class Redeclarable {
|
||||
|
||||
protected:
|
||||
// FIXME: PointerIntPair is a value class that should not be inherited from.
|
||||
// This should change to using containment.
|
||||
struct DeclLink : public llvm::PointerIntPair<decl_type *, 1, bool> {
|
||||
class DeclLink {
|
||||
llvm::PointerIntPair<decl_type *, 1, bool> NextAndIsPrevious;
|
||||
public:
|
||||
DeclLink(decl_type *D, bool isLatest)
|
||||
: llvm::PointerIntPair<decl_type *, 1, bool>(D, isLatest) { }
|
||||
: NextAndIsPrevious(D, isLatest) { }
|
||||
|
||||
typedef llvm::PointerIntPair<decl_type *, 1, bool> base_type;
|
||||
|
||||
bool NextIsPrevious() const { return base_type::getInt() == false; }
|
||||
bool NextIsLatest() const { return base_type::getInt() == true; }
|
||||
decl_type *getNext() const { return base_type::getPointer(); }
|
||||
bool NextIsPrevious() const { return !NextAndIsPrevious.getInt(); }
|
||||
bool NextIsLatest() const { return NextAndIsPrevious.getInt(); }
|
||||
decl_type *getNext() const { return NextAndIsPrevious.getPointer(); }
|
||||
void setNext(decl_type *D) { NextAndIsPrevious.setPointer(D); }
|
||||
};
|
||||
|
||||
struct PreviousDeclLink : public DeclLink {
|
||||
PreviousDeclLink(decl_type *D) : DeclLink(D, false) { }
|
||||
};
|
||||
static DeclLink PreviousDeclLink(decl_type *D) {
|
||||
return DeclLink(D, false);
|
||||
}
|
||||
|
||||
struct LatestDeclLink : public DeclLink {
|
||||
LatestDeclLink(decl_type *D) : DeclLink(D, true) { }
|
||||
};
|
||||
static DeclLink LatestDeclLink(decl_type *D) {
|
||||
return DeclLink(D, true);
|
||||
}
|
||||
|
||||
/// \brief Points to the next redeclaration in the chain.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -19,8 +19,8 @@
|
|||
#include "clang/AST/PrettyPrinter.h"
|
||||
#include "clang/AST/StmtIterator.h"
|
||||
#include "clang/AST/DeclGroup.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/AST/Attr.h"
|
||||
#include "clang/Lex/Token.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
|
@ -37,9 +37,11 @@ namespace clang {
|
|||
class ParmVarDecl;
|
||||
class QualType;
|
||||
class IdentifierInfo;
|
||||
class LabelDecl;
|
||||
class SourceManager;
|
||||
class StringLiteral;
|
||||
class SwitchStmt;
|
||||
class VarDecl;
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// ExprIterator - Iterators for iterating over Stmt* arrays that contain
|
||||
|
|
@ -499,6 +501,14 @@ public:
|
|||
decl_iterator decl_end() { return DG.end(); }
|
||||
const_decl_iterator decl_begin() const { return DG.begin(); }
|
||||
const_decl_iterator decl_end() const { return DG.end(); }
|
||||
|
||||
typedef std::reverse_iterator<decl_iterator> reverse_decl_iterator;
|
||||
reverse_decl_iterator decl_rbegin() {
|
||||
return reverse_decl_iterator(decl_end());
|
||||
}
|
||||
reverse_decl_iterator decl_rend() {
|
||||
return reverse_decl_iterator(decl_begin());
|
||||
}
|
||||
};
|
||||
|
||||
/// NullStmt - This is the null statement ";": C99 6.8.3p3.
|
||||
|
|
@ -545,20 +555,13 @@ class CompoundStmt : public Stmt {
|
|||
Stmt** Body;
|
||||
SourceLocation LBracLoc, RBracLoc;
|
||||
public:
|
||||
CompoundStmt(ASTContext& C, Stmt **StmtStart, unsigned NumStmts,
|
||||
SourceLocation LB, SourceLocation RB)
|
||||
: Stmt(CompoundStmtClass), LBracLoc(LB), RBracLoc(RB) {
|
||||
CompoundStmtBits.NumStmts = NumStmts;
|
||||
assert(CompoundStmtBits.NumStmts == NumStmts &&
|
||||
"NumStmts doesn't fit in bits of CompoundStmtBits.NumStmts!");
|
||||
CompoundStmt(ASTContext &C, Stmt **StmtStart, unsigned NumStmts,
|
||||
SourceLocation LB, SourceLocation RB);
|
||||
|
||||
if (NumStmts == 0) {
|
||||
Body = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
Body = new (C) Stmt*[NumStmts];
|
||||
memcpy(Body, StmtStart, NumStmts * sizeof(*Body));
|
||||
// \brief Build an empty compound statment with a location.
|
||||
explicit CompoundStmt(SourceLocation Loc)
|
||||
: Stmt(CompoundStmtClass), Body(0), LBracLoc(Loc), RBracLoc(Loc) {
|
||||
CompoundStmtBits.NumStmts = 0;
|
||||
}
|
||||
|
||||
// \brief Build an empty compound statement.
|
||||
|
|
@ -803,24 +806,32 @@ public:
|
|||
class AttributedStmt : public Stmt {
|
||||
Stmt *SubStmt;
|
||||
SourceLocation AttrLoc;
|
||||
AttrVec Attrs;
|
||||
// TODO: It can be done as Attr *Attrs[1]; and variable size array as in
|
||||
// StringLiteral
|
||||
unsigned NumAttrs;
|
||||
const Attr *Attrs[1];
|
||||
|
||||
friend class ASTStmtReader;
|
||||
|
||||
public:
|
||||
AttributedStmt(SourceLocation loc, const AttrVec &attrs, Stmt *substmt)
|
||||
: Stmt(AttributedStmtClass), SubStmt(substmt), AttrLoc(loc), Attrs(attrs) {
|
||||
AttributedStmt(SourceLocation Loc, ArrayRef<const Attr*> Attrs, Stmt *SubStmt)
|
||||
: Stmt(AttributedStmtClass), SubStmt(SubStmt), AttrLoc(Loc),
|
||||
NumAttrs(Attrs.size()) {
|
||||
memcpy(this->Attrs, Attrs.data(), Attrs.size() * sizeof(Attr*));
|
||||
}
|
||||
|
||||
// \brief Build an empty attributed statement.
|
||||
explicit AttributedStmt(EmptyShell Empty)
|
||||
: Stmt(AttributedStmtClass, Empty) {
|
||||
explicit AttributedStmt(EmptyShell Empty, unsigned NumAttrs)
|
||||
: Stmt(AttributedStmtClass, Empty), NumAttrs(NumAttrs) {
|
||||
memset(Attrs, 0, NumAttrs * sizeof(Attr*));
|
||||
}
|
||||
|
||||
public:
|
||||
static AttributedStmt *Create(ASTContext &C, SourceLocation Loc,
|
||||
ArrayRef<const Attr*> Attrs, Stmt *SubStmt);
|
||||
// \brief Build an empty attributed statement.
|
||||
static AttributedStmt *CreateEmpty(ASTContext &C, unsigned NumAttrs);
|
||||
|
||||
SourceLocation getAttrLoc() const { return AttrLoc; }
|
||||
const AttrVec &getAttrs() const { return Attrs; }
|
||||
ArrayRef<const Attr*> getAttrs() const {
|
||||
return ArrayRef<const Attr*>(Attrs, NumAttrs);
|
||||
}
|
||||
Stmt *getSubStmt() { return SubStmt; }
|
||||
const Stmt *getSubStmt() const { return SubStmt; }
|
||||
|
||||
|
|
@ -1606,6 +1617,69 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
/// MSAsmStmt - This represents a MS inline-assembly statement extension.
|
||||
///
|
||||
class MSAsmStmt : public Stmt {
|
||||
SourceLocation AsmLoc, EndLoc;
|
||||
std::string AsmStr;
|
||||
|
||||
bool IsSimple;
|
||||
bool IsVolatile;
|
||||
|
||||
unsigned NumAsmToks;
|
||||
unsigned NumLineEnds;
|
||||
unsigned NumClobbers;
|
||||
|
||||
Token *AsmToks;
|
||||
unsigned *LineEnds;
|
||||
Stmt **Exprs;
|
||||
StringRef *Clobbers;
|
||||
|
||||
public:
|
||||
MSAsmStmt(ASTContext &C, SourceLocation asmloc, bool issimple,
|
||||
bool isvolatile, ArrayRef<Token> asmtoks,
|
||||
ArrayRef<unsigned> lineends, StringRef asmstr,
|
||||
ArrayRef<StringRef> clobbers, SourceLocation endloc);
|
||||
|
||||
SourceLocation getAsmLoc() const { return AsmLoc; }
|
||||
void setAsmLoc(SourceLocation L) { AsmLoc = L; }
|
||||
SourceLocation getEndLoc() const { return EndLoc; }
|
||||
void setEndLoc(SourceLocation L) { EndLoc = L; }
|
||||
|
||||
unsigned getNumAsmToks() { return NumAsmToks; }
|
||||
Token *getAsmToks() { return AsmToks; }
|
||||
unsigned getNumLineEnds() { return NumLineEnds; }
|
||||
unsigned *getLineEnds() { return LineEnds; }
|
||||
|
||||
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(); }
|
||||
|
||||
//===--- Other ---===//
|
||||
|
||||
unsigned getNumClobbers() const { return NumClobbers; }
|
||||
StringRef getClobber(unsigned i) { return Clobbers[i]; }
|
||||
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
return SourceRange(AsmLoc, EndLoc);
|
||||
}
|
||||
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]);
|
||||
}
|
||||
};
|
||||
|
||||
class SEHExceptStmt : public Stmt {
|
||||
SourceLocation Loc;
|
||||
Stmt *Children[2];
|
||||
|
|
|
|||
|
|
@ -6,10 +6,9 @@
|
|||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the Objective-C statement AST node classes.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// \file
|
||||
/// \brief Defines the Objective-C statement AST node classes.
|
||||
|
||||
#ifndef LLVM_CLANG_AST_STMTOBJC_H
|
||||
#define LLVM_CLANG_AST_STMTOBJC_H
|
||||
|
|
@ -19,9 +18,9 @@
|
|||
|
||||
namespace clang {
|
||||
|
||||
/// ObjCForCollectionStmt - This represents Objective-c's collection statement;
|
||||
/// represented as 'for (element 'in' collection-expression)' stmt.
|
||||
/// \brief Represents Objective-C's collection statement.
|
||||
///
|
||||
/// This is represented as 'for (element 'in' collection-expression)' stmt.
|
||||
class ObjCForCollectionStmt : public Stmt {
|
||||
enum { ELEM, COLLECTION, BODY, END_EXPR };
|
||||
Stmt* SubExprs[END_EXPR]; // SubExprs[ELEM] is an expression or declstmt.
|
||||
|
|
@ -70,7 +69,7 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
/// ObjCAtCatchStmt - This represents objective-c's @catch statement.
|
||||
/// \brief Represents Objective-C's \@catch statement.
|
||||
class ObjCAtCatchStmt : public Stmt {
|
||||
private:
|
||||
VarDecl *ExceptionDecl;
|
||||
|
|
@ -118,7 +117,7 @@ public:
|
|||
child_range children() { return child_range(&Body, &Body + 1); }
|
||||
};
|
||||
|
||||
/// ObjCAtFinallyStmt - This represent objective-c's @finally Statement
|
||||
/// \brief Represents Objective-C's \@finally statement
|
||||
class ObjCAtFinallyStmt : public Stmt {
|
||||
Stmt *AtFinallyStmt;
|
||||
SourceLocation AtFinallyLoc;
|
||||
|
|
@ -151,24 +150,23 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
/// ObjCAtTryStmt - This represent objective-c's over-all
|
||||
/// @try ... @catch ... @finally statement.
|
||||
/// \brief Represents Objective-C's \@try ... \@catch ... \@finally statement.
|
||||
class ObjCAtTryStmt : public Stmt {
|
||||
private:
|
||||
// The location of the
|
||||
// The location of the @ in the \@try.
|
||||
SourceLocation AtTryLoc;
|
||||
|
||||
// The number of catch blocks in this statement.
|
||||
unsigned NumCatchStmts : 16;
|
||||
|
||||
// Whether this statement has a @finally statement.
|
||||
// Whether this statement has a \@finally statement.
|
||||
bool HasFinally : 1;
|
||||
|
||||
/// \brief Retrieve the statements that are stored after this @try statement.
|
||||
/// \brief Retrieve the statements that are stored after this \@try statement.
|
||||
///
|
||||
/// The order of the statements in memory follows the order in the source,
|
||||
/// with the @try body first, followed by the @catch statements (if any) and,
|
||||
/// finally, the @finally (if it exists).
|
||||
/// with the \@try body first, followed by the \@catch statements (if any)
|
||||
/// and, finally, the \@finally (if it exists).
|
||||
Stmt **getStmts() { return reinterpret_cast<Stmt **> (this + 1); }
|
||||
const Stmt* const *getStmts() const {
|
||||
return reinterpret_cast<const Stmt * const*> (this + 1);
|
||||
|
|
@ -192,26 +190,26 @@ public:
|
|||
unsigned NumCatchStmts,
|
||||
bool HasFinally);
|
||||
|
||||
/// \brief Retrieve the location of the @ in the @try.
|
||||
/// \brief Retrieve the location of the @ in the \@try.
|
||||
SourceLocation getAtTryLoc() const { return AtTryLoc; }
|
||||
void setAtTryLoc(SourceLocation Loc) { AtTryLoc = Loc; }
|
||||
|
||||
/// \brief Retrieve the @try body.
|
||||
/// \brief Retrieve the \@try body.
|
||||
const Stmt *getTryBody() const { return getStmts()[0]; }
|
||||
Stmt *getTryBody() { return getStmts()[0]; }
|
||||
void setTryBody(Stmt *S) { getStmts()[0] = S; }
|
||||
|
||||
/// \brief Retrieve the number of @catch statements in this try-catch-finally
|
||||
/// \brief Retrieve the number of \@catch statements in this try-catch-finally
|
||||
/// block.
|
||||
unsigned getNumCatchStmts() const { return NumCatchStmts; }
|
||||
|
||||
/// \brief Retrieve a @catch statement.
|
||||
/// \brief Retrieve a \@catch statement.
|
||||
const ObjCAtCatchStmt *getCatchStmt(unsigned I) const {
|
||||
assert(I < NumCatchStmts && "Out-of-bounds @catch index");
|
||||
return cast_or_null<ObjCAtCatchStmt>(getStmts()[I + 1]);
|
||||
}
|
||||
|
||||
/// \brief Retrieve a @catch statement.
|
||||
/// \brief Retrieve a \@catch statement.
|
||||
ObjCAtCatchStmt *getCatchStmt(unsigned I) {
|
||||
assert(I < NumCatchStmts && "Out-of-bounds @catch index");
|
||||
return cast_or_null<ObjCAtCatchStmt>(getStmts()[I + 1]);
|
||||
|
|
@ -223,7 +221,7 @@ public:
|
|||
getStmts()[I + 1] = S;
|
||||
}
|
||||
|
||||
/// Retrieve the @finally statement, if any.
|
||||
/// \brief Retrieve the \@finally statement, if any.
|
||||
const ObjCAtFinallyStmt *getFinallyStmt() const {
|
||||
if (!HasFinally)
|
||||
return 0;
|
||||
|
|
@ -254,11 +252,14 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
/// ObjCAtSynchronizedStmt - This is for objective-c's @synchronized statement.
|
||||
/// Example: @synchronized (sem) {
|
||||
/// do-something;
|
||||
/// }
|
||||
/// \brief Represents Objective-C's \@synchronized statement.
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// @synchronized (sem) {
|
||||
/// do-something;
|
||||
/// }
|
||||
/// \endcode
|
||||
class ObjCAtSynchronizedStmt : public Stmt {
|
||||
private:
|
||||
enum { SYNC_EXPR, SYNC_BODY, END_EXPR };
|
||||
|
|
@ -309,7 +310,7 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
/// ObjCAtThrowStmt - This represents objective-c's @throw statement.
|
||||
/// \brief Represents Objective-C's \@throw statement.
|
||||
class ObjCAtThrowStmt : public Stmt {
|
||||
Stmt *Throw;
|
||||
SourceLocation AtThrowLoc;
|
||||
|
|
@ -343,8 +344,7 @@ public:
|
|||
child_range children() { return child_range(&Throw, &Throw+1); }
|
||||
};
|
||||
|
||||
/// ObjCAutoreleasePoolStmt - This represent objective-c's
|
||||
/// @autoreleasepool Statement
|
||||
/// \brief Represents Objective-C's \@autoreleasepool Statement
|
||||
class ObjCAutoreleasePoolStmt : public Stmt {
|
||||
Stmt *SubStmt;
|
||||
SourceLocation AtLoc;
|
||||
|
|
|
|||
|
|
@ -73,7 +73,15 @@ private:
|
|||
union {
|
||||
uintptr_t TypeOrValue;
|
||||
struct {
|
||||
char Value[sizeof(llvm::APSInt)];
|
||||
// We store a decomposed APSInt with the data allocated by ASTContext if
|
||||
// BitWidth > 64. The memory may be shared between multiple
|
||||
// TemplateArgument instances.
|
||||
union {
|
||||
uint64_t VAL; ///< Used to store the <= 64 bits integer value.
|
||||
const uint64_t *pVal; ///< Used to store the >64 bits integer value.
|
||||
};
|
||||
unsigned BitWidth : 31;
|
||||
unsigned IsUnsigned : 1;
|
||||
void *Type;
|
||||
} Integer;
|
||||
struct {
|
||||
|
|
@ -104,11 +112,15 @@ public:
|
|||
TypeOrValue = reinterpret_cast<uintptr_t>(D);
|
||||
}
|
||||
|
||||
/// \brief Construct an integral constant template argument.
|
||||
TemplateArgument(const llvm::APSInt &Value, QualType Type) : Kind(Integral) {
|
||||
// FIXME: Large integral values will get leaked. Do something
|
||||
// similar to what we did with IntegerLiteral.
|
||||
new (Integer.Value) llvm::APSInt(Value);
|
||||
/// \brief Construct an integral constant template argument. The memory to
|
||||
/// store the value is allocated with Ctx.
|
||||
TemplateArgument(ASTContext &Ctx, const llvm::APSInt &Value, QualType Type);
|
||||
|
||||
/// \brief Construct an integral constant template argument with the same
|
||||
/// value as Other but a different type.
|
||||
TemplateArgument(const TemplateArgument &Other, QualType Type)
|
||||
: Kind(Integral) {
|
||||
Integer = Other.Integer;
|
||||
Integer.Type = Type.getAsOpaquePtr();
|
||||
}
|
||||
|
||||
|
|
@ -165,62 +177,6 @@ public:
|
|||
this->Args.NumArgs = NumArgs;
|
||||
}
|
||||
|
||||
/// \brief Copy constructor for a template argument.
|
||||
TemplateArgument(const TemplateArgument &Other) : Kind(Other.Kind) {
|
||||
// FIXME: Large integral values will get leaked. Do something
|
||||
// similar to what we did with IntegerLiteral.
|
||||
if (Kind == Integral) {
|
||||
new (Integer.Value) llvm::APSInt(*Other.getAsIntegral());
|
||||
Integer.Type = Other.Integer.Type;
|
||||
} else if (Kind == Pack) {
|
||||
Args.NumArgs = Other.Args.NumArgs;
|
||||
Args.Args = Other.Args.Args;
|
||||
} else if (Kind == Template || Kind == TemplateExpansion) {
|
||||
TemplateArg.Name = Other.TemplateArg.Name;
|
||||
TemplateArg.NumExpansions = Other.TemplateArg.NumExpansions;
|
||||
} else
|
||||
TypeOrValue = Other.TypeOrValue;
|
||||
}
|
||||
|
||||
TemplateArgument& operator=(const TemplateArgument& Other) {
|
||||
using llvm::APSInt;
|
||||
|
||||
if (Kind == Other.Kind && Kind == Integral) {
|
||||
// Copy integral values.
|
||||
*this->getAsIntegral() = *Other.getAsIntegral();
|
||||
Integer.Type = Other.Integer.Type;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Destroy the current integral value, if that's what we're holding.
|
||||
if (Kind == Integral)
|
||||
getAsIntegral()->~APSInt();
|
||||
|
||||
Kind = Other.Kind;
|
||||
|
||||
if (Other.Kind == Integral) {
|
||||
new (Integer.Value) llvm::APSInt(*Other.getAsIntegral());
|
||||
Integer.Type = Other.Integer.Type;
|
||||
} else if (Other.Kind == Pack) {
|
||||
Args.NumArgs = Other.Args.NumArgs;
|
||||
Args.Args = Other.Args.Args;
|
||||
} else if (Kind == Template || Kind == TemplateExpansion) {
|
||||
TemplateArg.Name = Other.TemplateArg.Name;
|
||||
TemplateArg.NumExpansions = Other.TemplateArg.NumExpansions;
|
||||
} else {
|
||||
TypeOrValue = Other.TypeOrValue;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
~TemplateArgument() {
|
||||
using llvm::APSInt;
|
||||
|
||||
if (Kind == Integral)
|
||||
getAsIntegral()->~APSInt();
|
||||
}
|
||||
|
||||
/// \brief Create a new template argument pack by copying the given set of
|
||||
/// template arguments.
|
||||
static TemplateArgument CreatePackCopy(ASTContext &Context,
|
||||
|
|
@ -286,14 +242,15 @@ public:
|
|||
llvm::Optional<unsigned> getNumTemplateExpansions() const;
|
||||
|
||||
/// \brief Retrieve the template argument as an integral value.
|
||||
llvm::APSInt *getAsIntegral() {
|
||||
if (Kind != Integral)
|
||||
return 0;
|
||||
return reinterpret_cast<llvm::APSInt*>(&Integer.Value[0]);
|
||||
}
|
||||
// FIXME: Provide a way to read the integral data without copying the value.
|
||||
llvm::APSInt getAsIntegral() const {
|
||||
using namespace llvm;
|
||||
if (Integer.BitWidth <= 64)
|
||||
return APSInt(APInt(Integer.BitWidth, Integer.VAL), Integer.IsUnsigned);
|
||||
|
||||
const llvm::APSInt *getAsIntegral() const {
|
||||
return const_cast<TemplateArgument*>(this)->getAsIntegral();
|
||||
unsigned NumWords = APInt::getNumWords(Integer.BitWidth);
|
||||
return APSInt(APInt(Integer.BitWidth, makeArrayRef(Integer.pVal, NumWords)),
|
||||
Integer.IsUnsigned);
|
||||
}
|
||||
|
||||
/// \brief Retrieve the type of the integral value.
|
||||
|
|
@ -342,14 +299,12 @@ public:
|
|||
return Args.NumArgs;
|
||||
}
|
||||
|
||||
/// Determines whether two template arguments are superficially the
|
||||
/// \brief Determines whether two template arguments are superficially the
|
||||
/// same.
|
||||
bool structurallyEquals(const TemplateArgument &Other) const;
|
||||
|
||||
/// \brief When the template argument is a pack expansion, returns
|
||||
/// \brief When the template argument is a pack expansion, returns
|
||||
/// the pattern of the pack expansion.
|
||||
///
|
||||
/// \param Ellipsis Will be set to the location of the ellipsis.
|
||||
TemplateArgument getPackExpansionPattern() const;
|
||||
|
||||
/// \brief Print this template argument to the given output stream.
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/ADT/PointerIntPair.h"
|
||||
#include "llvm/ADT/PointerUnion.h"
|
||||
#include "llvm/ADT/Twine.h"
|
||||
#include "clang/Basic/LLVM.h"
|
||||
|
||||
namespace clang {
|
||||
|
|
@ -377,8 +378,6 @@ public:
|
|||
return hasConst();
|
||||
}
|
||||
|
||||
bool isSupersetOf(Qualifiers Other) const;
|
||||
|
||||
/// \brief Determine whether this set of qualifiers is a strict superset of
|
||||
/// another set of qualifiers, not considering qualifier compatibility.
|
||||
bool isStrictSupersetOf(Qualifiers Other) const;
|
||||
|
|
@ -412,12 +411,11 @@ public:
|
|||
}
|
||||
|
||||
std::string getAsString() const;
|
||||
std::string getAsString(const PrintingPolicy &Policy) const {
|
||||
std::string Buffer;
|
||||
getAsStringInternal(Buffer, Policy);
|
||||
return Buffer;
|
||||
}
|
||||
void getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const;
|
||||
std::string getAsString(const PrintingPolicy &Policy) const;
|
||||
|
||||
bool isEmptyWhenPrinted(const PrintingPolicy &Policy) const;
|
||||
void print(raw_ostream &OS, const PrintingPolicy &Policy,
|
||||
bool appendSpaceIfNonEmpty = false) const;
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID) const {
|
||||
ID.AddInteger(Mask);
|
||||
|
|
@ -522,8 +520,6 @@ public:
|
|||
void setLocalFastQualifiers(unsigned Quals) { Value.setInt(Quals); }
|
||||
|
||||
/// Retrieves a pointer to the underlying (unqualified) type.
|
||||
/// This should really return a const Type, but it's not worth
|
||||
/// changing all the users right now.
|
||||
///
|
||||
/// This function requires that the type not be NULL. If the type might be
|
||||
/// NULL, use the (slightly less efficient) \c getTypePtrOrNull().
|
||||
|
|
@ -634,6 +630,11 @@ public:
|
|||
/// \brief Determine whether this is a Plain Old Data (POD) type (C++ 3.9p10).
|
||||
bool isPODType(ASTContext &Context) const;
|
||||
|
||||
/// isCXX98PODType() - Return true if this is a POD type according to the
|
||||
/// rules of the C++98 standard, regardless of the current compilation's
|
||||
/// language.
|
||||
bool isCXX98PODType(ASTContext &Context) const;
|
||||
|
||||
/// isCXX11PODType() - Return true if this is a POD type according to the
|
||||
/// more relaxed rules of the C++11 standard, regardless of the current
|
||||
/// compilation's language.
|
||||
|
|
@ -824,11 +825,20 @@ public:
|
|||
}
|
||||
static std::string getAsString(const Type *ty, Qualifiers qs);
|
||||
|
||||
std::string getAsString(const PrintingPolicy &Policy) const {
|
||||
std::string S;
|
||||
getAsStringInternal(S, Policy);
|
||||
return S;
|
||||
std::string getAsString(const PrintingPolicy &Policy) const;
|
||||
|
||||
void print(raw_ostream &OS, const PrintingPolicy &Policy,
|
||||
const Twine &PlaceHolder = Twine()) const {
|
||||
print(split(), OS, Policy, PlaceHolder);
|
||||
}
|
||||
static void print(SplitQualType split, raw_ostream &OS,
|
||||
const PrintingPolicy &policy, const Twine &PlaceHolder) {
|
||||
return print(split.Ty, split.Quals, OS, policy, PlaceHolder);
|
||||
}
|
||||
static void print(const Type *ty, Qualifiers qs,
|
||||
raw_ostream &OS, const PrintingPolicy &policy,
|
||||
const Twine &PlaceHolder);
|
||||
|
||||
void getAsStringInternal(std::string &Str,
|
||||
const PrintingPolicy &Policy) const {
|
||||
return getAsStringInternal(split(), Str, Policy);
|
||||
|
|
@ -841,6 +851,27 @@ public:
|
|||
std::string &out,
|
||||
const PrintingPolicy &policy);
|
||||
|
||||
class StreamedQualTypeHelper {
|
||||
const QualType &T;
|
||||
const PrintingPolicy &Policy;
|
||||
const Twine &PlaceHolder;
|
||||
public:
|
||||
StreamedQualTypeHelper(const QualType &T, const PrintingPolicy &Policy,
|
||||
const Twine &PlaceHolder)
|
||||
: T(T), Policy(Policy), PlaceHolder(PlaceHolder) { }
|
||||
|
||||
friend raw_ostream &operator<<(raw_ostream &OS,
|
||||
const StreamedQualTypeHelper &SQT) {
|
||||
SQT.T.print(OS, SQT.Policy, SQT.PlaceHolder);
|
||||
return OS;
|
||||
}
|
||||
};
|
||||
|
||||
StreamedQualTypeHelper stream(const PrintingPolicy &Policy,
|
||||
const Twine &PlaceHolder = Twine()) const {
|
||||
return StreamedQualTypeHelper(*this, Policy, PlaceHolder);
|
||||
}
|
||||
|
||||
void dump(const char *s) const;
|
||||
void dump() const;
|
||||
|
||||
|
|
@ -1107,8 +1138,6 @@ private:
|
|||
unsigned TC : 8;
|
||||
|
||||
/// Dependent - Whether this type is a dependent type (C++ [temp.dep.type]).
|
||||
/// Note that this should stay at the end of the ivars for Type so that
|
||||
/// subclasses can pack their bitfields into the same word.
|
||||
unsigned Dependent : 1;
|
||||
|
||||
/// \brief Whether this type somehow involves a template parameter, even
|
||||
|
|
@ -1614,7 +1643,7 @@ public:
|
|||
AutoType *getContainedAutoType() const;
|
||||
|
||||
/// Member-template getAs<specific type>'. Look through sugar for
|
||||
/// an instance of <specific type>. This scheme will eventually
|
||||
/// an instance of \<specific type>. This scheme will eventually
|
||||
/// replace the specific getAsXXXX methods above.
|
||||
///
|
||||
/// There are some specializations of this member template listed
|
||||
|
|
@ -1626,7 +1655,7 @@ public:
|
|||
const ArrayType *getAsArrayTypeUnsafe() const;
|
||||
|
||||
/// Member-template castAs<specific type>. Look through sugar for
|
||||
/// the underlying instance of <specific type>.
|
||||
/// the underlying instance of \<specific type>.
|
||||
///
|
||||
/// This method has the same relationship to getAs<T> as cast<T> has
|
||||
/// to dyn_cast<T>; which is to say, the underlying type *must*
|
||||
|
|
@ -1715,9 +1744,9 @@ public:
|
|||
friend class ASTWriter;
|
||||
};
|
||||
|
||||
template <> inline const TypedefType *Type::getAs() const {
|
||||
return dyn_cast<TypedefType>(this);
|
||||
}
|
||||
/// \brief This will check for a TypedefType by removing any existing sugar
|
||||
/// until it reaches a TypedefType or a non-sugared type.
|
||||
template <> const TypedefType *Type::getAs() const;
|
||||
|
||||
// We can do canonical leaf types faster, because we don't have to
|
||||
// worry about preserving child type decoration.
|
||||
|
|
@ -1752,7 +1781,13 @@ public:
|
|||
}
|
||||
|
||||
Kind getKind() const { return static_cast<Kind>(BuiltinTypeBits.Kind); }
|
||||
const char *getName(const PrintingPolicy &Policy) const;
|
||||
StringRef getName(const PrintingPolicy &Policy) const;
|
||||
const char *getNameAsCString(const PrintingPolicy &Policy) const {
|
||||
// The StringRef is null-terminated.
|
||||
StringRef str = getName(Policy);
|
||||
assert(!str.empty() && str.data()[str.size()] == '\0');
|
||||
return str.data();
|
||||
}
|
||||
|
||||
bool isSugared() const { return false; }
|
||||
QualType desugar() const { return QualType(this, 0); }
|
||||
|
|
@ -2641,6 +2676,9 @@ public:
|
|||
bool getNoReturnAttr() const { return getExtInfo().getNoReturn(); }
|
||||
CallingConv getCallConv() const { return getExtInfo().getCC(); }
|
||||
ExtInfo getExtInfo() const { return ExtInfo(FunctionTypeBits.ExtInfo); }
|
||||
bool isConst() const { return getTypeQuals() & Qualifiers::Const; }
|
||||
bool isVolatile() const { return getTypeQuals() & Qualifiers::Volatile; }
|
||||
bool isRestrict() const { return getTypeQuals() & Qualifiers::Restrict; }
|
||||
|
||||
/// \brief Determine the type of an expression that calls a function of
|
||||
/// this type.
|
||||
|
|
@ -2808,6 +2846,8 @@ public:
|
|||
} else if (EPI.ExceptionSpecType == EST_Uninstantiated) {
|
||||
EPI.ExceptionSpecDecl = getExceptionSpecDecl();
|
||||
EPI.ExceptionSpecTemplate = getExceptionSpecTemplate();
|
||||
} else if (EPI.ExceptionSpecType == EST_Unevaluated) {
|
||||
EPI.ExceptionSpecDecl = getExceptionSpecDecl();
|
||||
}
|
||||
if (hasAnyConsumedArgs())
|
||||
EPI.ConsumedArguments = getConsumedArgsBuffer();
|
||||
|
|
@ -2851,11 +2891,13 @@ public:
|
|||
// NoexceptExpr sits where the arguments end.
|
||||
return *reinterpret_cast<Expr *const *>(arg_type_end());
|
||||
}
|
||||
/// \brief If this function type has an uninstantiated exception
|
||||
/// specification, this is the function whose exception specification
|
||||
/// is represented by this type.
|
||||
/// \brief If this function type has an exception specification which hasn't
|
||||
/// been determined yet (either because it has not been evaluated or because
|
||||
/// it has not been instantiated), this is the function whose exception
|
||||
/// specification is represented by this type.
|
||||
FunctionDecl *getExceptionSpecDecl() const {
|
||||
if (getExceptionSpecType() != EST_Uninstantiated)
|
||||
if (getExceptionSpecType() != EST_Uninstantiated &&
|
||||
getExceptionSpecType() != EST_Unevaluated)
|
||||
return 0;
|
||||
return reinterpret_cast<FunctionDecl * const *>(arg_type_end())[0];
|
||||
}
|
||||
|
|
@ -2870,7 +2912,7 @@ public:
|
|||
}
|
||||
bool isNothrow(ASTContext &Ctx) const {
|
||||
ExceptionSpecificationType EST = getExceptionSpecType();
|
||||
assert(EST != EST_Delayed && EST != EST_Uninstantiated);
|
||||
assert(EST != EST_Unevaluated && EST != EST_Uninstantiated);
|
||||
if (EST == EST_DynamicNone || EST == EST_BasicNoexcept)
|
||||
return true;
|
||||
if (EST != EST_ComputedNoexcept)
|
||||
|
|
@ -2928,8 +2970,11 @@ public:
|
|||
bool isSugared() const { return false; }
|
||||
QualType desugar() const { return QualType(this, 0); }
|
||||
|
||||
// FIXME: Remove the string version.
|
||||
void printExceptionSpecification(std::string &S,
|
||||
PrintingPolicy Policy) const;
|
||||
void printExceptionSpecification(raw_ostream &OS,
|
||||
PrintingPolicy Policy) const;
|
||||
|
||||
static bool classof(const Type *T) {
|
||||
return T->getTypeClass() == FunctionProto;
|
||||
|
|
@ -3582,6 +3627,7 @@ public:
|
|||
|
||||
/// \brief Print a template argument list, including the '<' and '>'
|
||||
/// enclosing the template arguments.
|
||||
// FIXME: remove the string ones.
|
||||
static std::string PrintTemplateArgumentList(const TemplateArgument *Args,
|
||||
unsigned NumArgs,
|
||||
const PrintingPolicy &Policy,
|
||||
|
|
@ -3594,6 +3640,23 @@ public:
|
|||
static std::string PrintTemplateArgumentList(const TemplateArgumentListInfo &,
|
||||
const PrintingPolicy &Policy);
|
||||
|
||||
/// \brief Print a template argument list, including the '<' and '>'
|
||||
/// enclosing the template arguments.
|
||||
static void PrintTemplateArgumentList(raw_ostream &OS,
|
||||
const TemplateArgument *Args,
|
||||
unsigned NumArgs,
|
||||
const PrintingPolicy &Policy,
|
||||
bool SkipBrackets = false);
|
||||
|
||||
static void PrintTemplateArgumentList(raw_ostream &OS,
|
||||
const TemplateArgumentLoc *Args,
|
||||
unsigned NumArgs,
|
||||
const PrintingPolicy &Policy);
|
||||
|
||||
static void PrintTemplateArgumentList(raw_ostream &OS,
|
||||
const TemplateArgumentListInfo &,
|
||||
const PrintingPolicy &Policy);
|
||||
|
||||
/// True if this template specialization type matches a current
|
||||
/// instantiation in the context in which it is found.
|
||||
bool isCurrentInstantiation() const {
|
||||
|
|
@ -3641,7 +3704,7 @@ public:
|
|||
unsigned getNumArgs() const { return NumArgs; }
|
||||
|
||||
/// \brief Retrieve a specific template argument as a type.
|
||||
/// \precondition @c isArgType(Arg)
|
||||
/// \pre @c isArgType(Arg)
|
||||
const TemplateArgument &getArg(unsigned Idx) const; // in TemplateBase.h
|
||||
|
||||
bool isSugared() const {
|
||||
|
|
@ -4045,7 +4108,7 @@ class PackExpansionType : public Type, public llvm::FoldingSetNode {
|
|||
|
||||
PackExpansionType(QualType Pattern, QualType Canon,
|
||||
llvm::Optional<unsigned> NumExpansions)
|
||||
: Type(PackExpansion, Canon, /*Dependent=*/true,
|
||||
: Type(PackExpansion, Canon, /*Dependent=*/Pattern->isDependentType(),
|
||||
/*InstantiationDependent=*/true,
|
||||
/*VariableModified=*/Pattern->isVariablyModifiedType(),
|
||||
/*ContainsUnexpandedParameterPack=*/false),
|
||||
|
|
@ -4097,8 +4160,10 @@ public:
|
|||
/// list of protocols.
|
||||
///
|
||||
/// Given the following declarations:
|
||||
/// @class C;
|
||||
/// @protocol P;
|
||||
/// \code
|
||||
/// \@class C;
|
||||
/// \@protocol P;
|
||||
/// \endcode
|
||||
///
|
||||
/// 'C' is an ObjCInterfaceType C. It is sugar for an ObjCObjectType
|
||||
/// with base C and no protocols.
|
||||
|
|
@ -4312,11 +4377,13 @@ public:
|
|||
/// This method is equivalent to getPointeeType() except that
|
||||
/// it discards any typedefs (or other sugar) between this
|
||||
/// type and the "outermost" object type. So for:
|
||||
/// @class A; @protocol P; @protocol Q;
|
||||
/// \code
|
||||
/// \@class A; \@protocol P; \@protocol Q;
|
||||
/// typedef A<P> AP;
|
||||
/// typedef A A1;
|
||||
/// typedef A1<P> A1P;
|
||||
/// typedef A1P<Q> A1PQ;
|
||||
/// \endcode
|
||||
/// For 'A*', getObjectType() will return 'A'.
|
||||
/// For 'A<P>*', getObjectType() will return 'A<P>'.
|
||||
/// For 'AP*', getObjectType() will return 'A<P>'.
|
||||
|
|
@ -4333,7 +4400,7 @@ public:
|
|||
}
|
||||
|
||||
/// getInterfaceType - If this pointer points to an Objective C
|
||||
/// @interface type, gets the type for that interface. Any protocol
|
||||
/// \@interface type, gets the type for that interface. Any protocol
|
||||
/// qualifiers on the interface are ignored.
|
||||
///
|
||||
/// \return null if the base type for this pointer is 'id' or 'Class'
|
||||
|
|
@ -4341,7 +4408,7 @@ public:
|
|||
return getObjectType()->getBaseType()->getAs<ObjCInterfaceType>();
|
||||
}
|
||||
|
||||
/// getInterfaceDecl - If this pointer points to an Objective @interface
|
||||
/// getInterfaceDecl - If this pointer points to an Objective \@interface
|
||||
/// type, gets the declaration for that interface.
|
||||
///
|
||||
/// \return null if the base type for this pointer is 'id' or 'Class'
|
||||
|
|
@ -4970,7 +5037,7 @@ struct ArrayType_cannot_be_used_with_getAs { };
|
|||
template<typename T>
|
||||
struct ArrayType_cannot_be_used_with_getAs<T, true>;
|
||||
|
||||
/// Member-template getAs<specific type>'.
|
||||
// Member-template getAs<specific type>'.
|
||||
template <typename T> const T *Type::getAs() const {
|
||||
ArrayType_cannot_be_used_with_getAs<T> at;
|
||||
(void)at;
|
||||
|
|
|
|||
|
|
@ -831,6 +831,7 @@ public:
|
|||
|
||||
struct ObjCInterfaceLocInfo {
|
||||
SourceLocation NameLoc;
|
||||
SourceLocation NameEndLoc;
|
||||
};
|
||||
|
||||
/// \brief Wrapper for source info for ObjC interfaces.
|
||||
|
|
@ -850,9 +851,17 @@ public:
|
|||
void setNameLoc(SourceLocation Loc) {
|
||||
getLocalData()->NameLoc = Loc;
|
||||
}
|
||||
|
||||
|
||||
SourceRange getLocalSourceRange() const {
|
||||
return SourceRange(getNameLoc());
|
||||
return SourceRange(getNameLoc(), getNameEndLoc());
|
||||
}
|
||||
|
||||
SourceLocation getNameEndLoc() const {
|
||||
return getLocalData()->NameEndLoc;
|
||||
}
|
||||
|
||||
void setNameEndLoc(SourceLocation Loc) {
|
||||
getLocalData()->NameEndLoc = Loc;
|
||||
}
|
||||
|
||||
void initializeLocal(ASTContext &Context, SourceLocation Loc) {
|
||||
|
|
|
|||
141
include/clang/ASTMatchers/ASTMatchFinder.h
Normal file
141
include/clang/ASTMatchers/ASTMatchFinder.h
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
//===--- ASTMatchFinder.h - Structural query framework ----------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Provides a way to construct an ASTConsumer that runs given matchers
|
||||
// over the AST and invokes a given callback on every match.
|
||||
//
|
||||
// The general idea is to construct a matcher expression that describes a
|
||||
// subtree match on the AST. Next, a callback that is executed every time the
|
||||
// expression matches is registered, and the matcher is run over the AST of
|
||||
// some code. Matched subexpressions can be bound to string IDs and easily
|
||||
// be accessed from the registered callback. The callback can than use the
|
||||
// AST nodes that the subexpressions matched on to output information about
|
||||
// the match or construct changes that can be applied to the code.
|
||||
//
|
||||
// Example:
|
||||
// class HandleMatch : public MatchFinder::MatchCallback {
|
||||
// public:
|
||||
// virtual void Run(const MatchFinder::MatchResult &Result) {
|
||||
// const CXXRecordDecl *Class =
|
||||
// Result.Nodes.GetDeclAs<CXXRecordDecl>("id");
|
||||
// ...
|
||||
// }
|
||||
// };
|
||||
//
|
||||
// int main(int argc, char **argv) {
|
||||
// ClangTool Tool(argc, argv);
|
||||
// MatchFinder finder;
|
||||
// finder.AddMatcher(Id("id", record(hasName("::a_namespace::AClass"))),
|
||||
// new HandleMatch);
|
||||
// return Tool.Run(newFrontendActionFactory(&finder));
|
||||
// }
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_MATCHERS_AST_MATCH_FINDER_H
|
||||
#define LLVM_CLANG_AST_MATCHERS_AST_MATCH_FINDER_H
|
||||
|
||||
#include "clang/ASTMatchers/ASTMatchers.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
namespace ast_matchers {
|
||||
|
||||
/// \brief A class to allow finding matches over the Clang AST.
|
||||
///
|
||||
/// After creation, you can add multiple matchers to the MatchFinder via
|
||||
/// calls to addMatcher(...).
|
||||
///
|
||||
/// Once all matchers are added, newASTConsumer() returns an ASTConsumer
|
||||
/// that will trigger the callbacks specified via addMatcher(...) when a match
|
||||
/// is found.
|
||||
///
|
||||
/// See ASTMatchers.h for more information about how to create matchers.
|
||||
///
|
||||
/// Not intended to be subclassed.
|
||||
class MatchFinder {
|
||||
public:
|
||||
/// \brief Contains all information for a given match.
|
||||
///
|
||||
/// Every time a match is found, the MatchFinder will invoke the registered
|
||||
/// MatchCallback with a MatchResult containing information about the match.
|
||||
struct MatchResult {
|
||||
MatchResult(const BoundNodes &Nodes, clang::ASTContext *Context);
|
||||
|
||||
/// \brief Contains the nodes bound on the current match.
|
||||
///
|
||||
/// This allows user code to easily extract matched AST nodes.
|
||||
const BoundNodes Nodes;
|
||||
|
||||
/// \brief Utilities for interpreting the matched AST structures.
|
||||
/// @{
|
||||
clang::ASTContext * const Context;
|
||||
clang::SourceManager * const SourceManager;
|
||||
/// @}
|
||||
};
|
||||
|
||||
/// \brief Called when the Match registered for it was successfully found
|
||||
/// in the AST.
|
||||
class MatchCallback {
|
||||
public:
|
||||
virtual ~MatchCallback();
|
||||
virtual void run(const MatchResult &Result) = 0;
|
||||
};
|
||||
|
||||
/// \brief Called when parsing is finished. Intended for testing only.
|
||||
class ParsingDoneTestCallback {
|
||||
public:
|
||||
virtual ~ParsingDoneTestCallback();
|
||||
virtual void run() = 0;
|
||||
};
|
||||
|
||||
MatchFinder();
|
||||
~MatchFinder();
|
||||
|
||||
/// \brief Adds a matcher to execute when running over the AST.
|
||||
///
|
||||
/// Calls 'Action' with the BoundNodes on every match.
|
||||
/// Adding more than one 'NodeMatch' allows finding different matches in a
|
||||
/// single pass over the AST.
|
||||
///
|
||||
/// Does not take ownership of 'Action'.
|
||||
/// @{
|
||||
void addMatcher(const DeclarationMatcher &NodeMatch,
|
||||
MatchCallback *Action);
|
||||
void addMatcher(const TypeMatcher &NodeMatch,
|
||||
MatchCallback *Action);
|
||||
void addMatcher(const StatementMatcher &NodeMatch,
|
||||
MatchCallback *Action);
|
||||
/// @}
|
||||
|
||||
/// \brief Creates a clang ASTConsumer that finds all matches.
|
||||
clang::ASTConsumer *newASTConsumer();
|
||||
|
||||
/// \brief Registers a callback to notify the end of parsing.
|
||||
///
|
||||
/// The provided closure is called after parsing is done, before the AST is
|
||||
/// traversed. Useful for benchmarking.
|
||||
/// Each call to FindAll(...) will call the closure once.
|
||||
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 Called when parsing is done.
|
||||
ParsingDoneTestCallback *ParsingDone;
|
||||
};
|
||||
|
||||
} // end namespace ast_matchers
|
||||
} // end namespace clang
|
||||
|
||||
#endif // LLVM_CLANG_AST_MATCHERS_AST_MATCH_FINDER_H
|
||||
1799
include/clang/ASTMatchers/ASTMatchers.h
Normal file
1799
include/clang/ASTMatchers/ASTMatchers.h
Normal file
File diff suppressed because it is too large
Load diff
901
include/clang/ASTMatchers/ASTMatchersInternal.h
Normal file
901
include/clang/ASTMatchers/ASTMatchersInternal.h
Normal file
|
|
@ -0,0 +1,901 @@
|
|||
//===--- ASTMatchersInternal.h - Structural query framework -----*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Implements the base layer of the matcher framework.
|
||||
//
|
||||
// Matchers are methods that return a Matcher<T> which provides a method
|
||||
// Matches(...) which is a predicate on an AST node. The Matches method's
|
||||
// parameters define the context of the match, which allows matchers to recurse
|
||||
// or store the current node as bound to a specific string, so that it can be
|
||||
// retrieved later.
|
||||
//
|
||||
// In general, matchers have two parts:
|
||||
// 1. A function Matcher<T> MatcherName(<arguments>) which returns a Matcher<T>
|
||||
// based on the arguments and optionally on template type deduction based
|
||||
// on the arguments. Matcher<T>s form an implicit reverse hierarchy
|
||||
// to clang's AST class hierarchy, meaning that you can use a Matcher<Base>
|
||||
// everywhere a Matcher<Derived> is required.
|
||||
// 2. An implementation of a class derived from MatcherInterface<T>.
|
||||
//
|
||||
// The matcher functions are defined in ASTMatchers.h. To make it possible
|
||||
// to implement both the matcher function and the implementation of the matcher
|
||||
// interface in one place, ASTMatcherMacros.h defines macros that allow
|
||||
// implementing a matcher in a single place.
|
||||
//
|
||||
// This file contains the base classes needed to construct the actual matchers.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_INTERNAL_H
|
||||
#define LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_INTERNAL_H
|
||||
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/DeclCXX.h"
|
||||
#include "clang/AST/ExprCXX.h"
|
||||
#include "clang/AST/Stmt.h"
|
||||
#include "llvm/ADT/VariadicFunction.h"
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace clang {
|
||||
namespace ast_matchers {
|
||||
|
||||
/// FIXME: Move into the llvm support library.
|
||||
template <bool> struct CompileAssert {};
|
||||
#define TOOLING_COMPILE_ASSERT(Expr, Msg) \
|
||||
typedef CompileAssert<(bool(Expr))> Msg[bool(Expr) ? 1 : -1]
|
||||
|
||||
class BoundNodes;
|
||||
|
||||
namespace internal {
|
||||
|
||||
class BoundNodesTreeBuilder;
|
||||
|
||||
/// \brief A tree of bound nodes in match results.
|
||||
///
|
||||
/// If a match can contain multiple matches on the same node with different
|
||||
/// matching subexpressions, BoundNodesTree contains a branch for each of
|
||||
/// those matching subexpressions.
|
||||
///
|
||||
/// BoundNodesTree's are created during the matching process; when a match
|
||||
/// is found, we iterate over the tree and create a BoundNodes object containing
|
||||
/// the union of all bound nodes on the path from the root to a each leaf.
|
||||
class BoundNodesTree {
|
||||
public:
|
||||
/// \brief A visitor interface to visit all BoundNodes results for a
|
||||
/// BoundNodesTree.
|
||||
class Visitor {
|
||||
public:
|
||||
virtual ~Visitor() {}
|
||||
|
||||
/// \brief Called multiple times during a single call to VisitMatches(...).
|
||||
///
|
||||
/// 'BoundNodesView' contains the bound nodes for a single match.
|
||||
virtual void visitMatch(const BoundNodes& BoundNodesView) = 0;
|
||||
};
|
||||
|
||||
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,
|
||||
const std::vector<BoundNodesTree> RecursiveBindings);
|
||||
|
||||
/// \brief Adds all bound nodes to bound_nodes_builder.
|
||||
void copyTo(BoundNodesTreeBuilder* Builder) const;
|
||||
|
||||
/// \brief Visits all matches that this BoundNodesTree represents.
|
||||
///
|
||||
/// The ownership of 'ResultVisitor' remains at the caller.
|
||||
void visitMatches(Visitor* ResultVisitor);
|
||||
|
||||
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;
|
||||
|
||||
// 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;
|
||||
|
||||
std::vector<BoundNodesTree> RecursiveBindings;
|
||||
};
|
||||
|
||||
/// \brief Creates BoundNodesTree objects.
|
||||
///
|
||||
/// The tree builder is used during the matching process to insert the bound
|
||||
/// nodes from the Id matcher.
|
||||
class BoundNodesTreeBuilder {
|
||||
public:
|
||||
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);
|
||||
/// @}
|
||||
|
||||
/// \brief Adds a branch in the tree.
|
||||
void addMatch(const BoundNodesTree& Bindings);
|
||||
|
||||
/// \brief Returns a BoundNodes object containing all current bindings.
|
||||
BoundNodesTree build() const;
|
||||
|
||||
private:
|
||||
BoundNodesTreeBuilder(const BoundNodesTreeBuilder&); // DO NOT IMPLEMENT
|
||||
void operator=(const BoundNodesTreeBuilder&); // DO NOT IMPLEMENT
|
||||
|
||||
std::map<std::string, const Decl*> DeclBindings;
|
||||
std::map<std::string, const Stmt*> StmtBindings;
|
||||
|
||||
std::vector<BoundNodesTree> RecursiveBindings;
|
||||
};
|
||||
|
||||
class ASTMatchFinder;
|
||||
|
||||
/// \brief Generic interface for matchers on an AST node of type T.
|
||||
///
|
||||
/// Implement this if your matcher may need to inspect the children or
|
||||
/// descendants of the node or bind matched nodes to names. If you are
|
||||
/// writing a simple matcher that only inspects properties of the
|
||||
/// current node and doesn't care about its children or descendants,
|
||||
/// implement SingleNodeMatcherInterface instead.
|
||||
template <typename T>
|
||||
class MatcherInterface : public llvm::RefCountedBaseVPTR {
|
||||
public:
|
||||
virtual ~MatcherInterface() {}
|
||||
|
||||
/// \brief Returns true if 'Node' can be matched.
|
||||
///
|
||||
/// May bind 'Node' to an ID via 'Builder', or recurse into
|
||||
/// the AST via 'Finder'.
|
||||
virtual bool matches(const T &Node,
|
||||
ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const = 0;
|
||||
};
|
||||
|
||||
/// \brief Interface for matchers that only evaluate properties on a single node.
|
||||
template <typename T>
|
||||
class SingleNodeMatcherInterface : public MatcherInterface<T> {
|
||||
public:
|
||||
/// \brief Returns true if the matcher matches the provided node.
|
||||
///
|
||||
/// A subclass must implement this instead of Matches().
|
||||
virtual bool matchesNode(const T &Node) const = 0;
|
||||
|
||||
private:
|
||||
/// Implements MatcherInterface::Matches.
|
||||
virtual bool matches(const T &Node,
|
||||
ASTMatchFinder * /* Finder */,
|
||||
BoundNodesTreeBuilder * /* Builder */) const {
|
||||
return matchesNode(Node);
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief Wrapper of a MatcherInterface<T> *that allows copying.
|
||||
///
|
||||
/// A Matcher<Base> can be used anywhere a Matcher<Derived> is
|
||||
/// required. This establishes an is-a relationship which is reverse
|
||||
/// to the AST hierarchy. In other words, Matcher<T> is contravariant
|
||||
/// with respect to T. The relationship is built via a type conversion
|
||||
/// operator rather than a type hierarchy to be able to templatize the
|
||||
/// type hierarchy instead of spelling it out.
|
||||
template <typename T>
|
||||
class Matcher {
|
||||
public:
|
||||
/// \brief Takes ownership of the provided implementation pointer.
|
||||
explicit Matcher(MatcherInterface<T> *Implementation)
|
||||
: Implementation(Implementation) {}
|
||||
|
||||
/// \brief Forwards the call to the underlying MatcherInterface<T> pointer.
|
||||
bool matches(const T &Node,
|
||||
ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
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
|
||||
/// implementations (no new() implementation_ during a Matches()).
|
||||
return reinterpret_cast<uint64_t>(Implementation.getPtr());
|
||||
}
|
||||
|
||||
private:
|
||||
/// \brief Allows conversion from Matcher<T> to Matcher<Derived> if Derived
|
||||
/// is derived from T.
|
||||
template <typename Derived>
|
||||
class ImplicitCastMatcher : public MatcherInterface<Derived> {
|
||||
public:
|
||||
explicit ImplicitCastMatcher(const Matcher<T> &From)
|
||||
: From(From) {}
|
||||
|
||||
virtual bool matches(const Derived &Node,
|
||||
ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
return From.matches(Node, Finder, Builder);
|
||||
}
|
||||
|
||||
private:
|
||||
const Matcher<T> From;
|
||||
};
|
||||
|
||||
llvm::IntrusiveRefCntPtr< MatcherInterface<T> > Implementation;
|
||||
}; // class Matcher
|
||||
|
||||
/// \brief A convenient helper for creating a Matcher<T> without specifying
|
||||
/// the template type argument.
|
||||
template <typename T>
|
||||
inline Matcher<T> makeMatcher(MatcherInterface<T> *Implementation) {
|
||||
return Matcher<T>(Implementation);
|
||||
}
|
||||
|
||||
/// \brief Matches declarations for QualType and CallExpr.
|
||||
///
|
||||
/// Type argument DeclMatcherT is required by PolymorphicMatcherWithParam1 but
|
||||
/// not actually used.
|
||||
template <typename T, typename DeclMatcherT>
|
||||
class HasDeclarationMatcher : public MatcherInterface<T> {
|
||||
TOOLING_COMPILE_ASSERT((llvm::is_same< DeclMatcherT,
|
||||
Matcher<Decl> >::value),
|
||||
instantiated_with_wrong_types);
|
||||
public:
|
||||
explicit HasDeclarationMatcher(const Matcher<Decl> &InnerMatcher)
|
||||
: InnerMatcher(InnerMatcher) {}
|
||||
|
||||
virtual bool matches(const T &Node,
|
||||
ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
return matchesSpecialized(Node, Finder, Builder);
|
||||
}
|
||||
|
||||
private:
|
||||
/// \brief Extracts the CXXRecordDecl of a QualType and returns whether the
|
||||
/// inner matcher matches on it.
|
||||
bool matchesSpecialized(const QualType &Node, ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
/// FIXME: Add other ways to convert...
|
||||
if (Node.isNull())
|
||||
return false;
|
||||
CXXRecordDecl *NodeAsRecordDecl = Node->getAsCXXRecordDecl();
|
||||
return NodeAsRecordDecl != NULL &&
|
||||
InnerMatcher.matches(*NodeAsRecordDecl, 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);
|
||||
}
|
||||
|
||||
/// \brief Extracts the Decl of the constructor call and returns whether the
|
||||
/// inner matcher matches on it.
|
||||
bool matchesSpecialized(const CXXConstructExpr &Node,
|
||||
ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
const Decl *NodeAsDecl = Node.getConstructor();
|
||||
return NodeAsDecl != NULL &&
|
||||
InnerMatcher.matches(*NodeAsDecl, 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).
|
||||
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, 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:
|
||||
/// Matches a matcher on every child node of the given node. Returns true
|
||||
/// if at least one child node could be matched.
|
||||
/// - matchesDescendantOf:
|
||||
/// Matches a matcher on all descendant nodes of the given node. Returns true
|
||||
/// if at least one descendant matched.
|
||||
class ASTMatchFinder {
|
||||
public:
|
||||
/// \brief Defines how we descend a level in the AST when we pass
|
||||
/// through expressions.
|
||||
enum TraversalKind {
|
||||
/// Will traverse any child nodes.
|
||||
TK_AsIs,
|
||||
/// Will not traverse implicit casts and parentheses.
|
||||
TK_IgnoreImplicitCastsAndParentheses
|
||||
};
|
||||
|
||||
/// \brief Defines how bindings are processed on recursive matches.
|
||||
enum BindKind {
|
||||
/// Stop at the first match and only bind the first match.
|
||||
BK_First,
|
||||
/// Create results for all combinations of bindings that match.
|
||||
BK_All
|
||||
};
|
||||
|
||||
virtual ~ASTMatchFinder() {}
|
||||
|
||||
/// \brief Returns true if the given class is directly or indirectly derived
|
||||
/// from a base type matching \c base.
|
||||
///
|
||||
/// A class is considered to be also derived from itself.
|
||||
virtual bool classIsDerivedFrom(const CXXRecordDecl *Declaration,
|
||||
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,
|
||||
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,
|
||||
BoundNodesTreeBuilder *Builder,
|
||||
BindKind Bind) = 0;
|
||||
};
|
||||
|
||||
/// \brief Converts a \c Matcher<T> to a matcher of desired type \c To by
|
||||
/// "adapting" a \c To into a \c T.
|
||||
///
|
||||
/// The \c ArgumentAdapterT argument specifies how the adaptation is done.
|
||||
///
|
||||
/// For example:
|
||||
/// \c ArgumentAdaptingMatcher<HasMatcher, T>(InnerMatcher);
|
||||
/// Given that \c InnerMatcher is of type \c Matcher<T>, this returns a matcher
|
||||
/// that is convertible into any matcher of type \c To by constructing
|
||||
/// \c HasMatcher<To, T>(InnerMatcher).
|
||||
///
|
||||
/// If a matcher does not need knowledge about the inner type, prefer to use
|
||||
/// PolymorphicMatcherWithParam1.
|
||||
template <template <typename ToArg, typename FromArg> class ArgumentAdapterT,
|
||||
typename T>
|
||||
class ArgumentAdaptingMatcher {
|
||||
public:
|
||||
explicit ArgumentAdaptingMatcher(const Matcher<T> &InnerMatcher)
|
||||
: InnerMatcher(InnerMatcher) {}
|
||||
|
||||
template <typename To>
|
||||
operator Matcher<To>() const {
|
||||
return Matcher<To>(new ArgumentAdapterT<To, T>(InnerMatcher));
|
||||
}
|
||||
|
||||
private:
|
||||
const Matcher<T> InnerMatcher;
|
||||
};
|
||||
|
||||
/// \brief A PolymorphicMatcherWithParamN<MatcherT, P1, ..., PN> object can be
|
||||
/// created from N parameters p1, ..., pN (of type P1, ..., PN) and
|
||||
/// used as a Matcher<T> where a MatcherT<T, P1, ..., PN>(p1, ..., pN)
|
||||
/// can be constructed.
|
||||
///
|
||||
/// For example:
|
||||
/// - PolymorphicMatcherWithParam0<IsDefinitionMatcher>()
|
||||
/// creates an object that can be used as a Matcher<T> for any type T
|
||||
/// where an IsDefinitionMatcher<T>() can be constructed.
|
||||
/// - PolymorphicMatcherWithParam1<ValueEqualsMatcher, int>(42)
|
||||
/// creates an object that can be used as a Matcher<T> for any type T
|
||||
/// where a ValueEqualsMatcher<T, int>(42) can be constructed.
|
||||
template <template <typename T> class MatcherT>
|
||||
class PolymorphicMatcherWithParam0 {
|
||||
public:
|
||||
template <typename T>
|
||||
operator Matcher<T>() const {
|
||||
return Matcher<T>(new MatcherT<T>());
|
||||
}
|
||||
};
|
||||
|
||||
template <template <typename T, typename P1> class MatcherT,
|
||||
typename P1>
|
||||
class PolymorphicMatcherWithParam1 {
|
||||
public:
|
||||
explicit PolymorphicMatcherWithParam1(const P1 &Param1)
|
||||
: Param1(Param1) {}
|
||||
|
||||
template <typename T>
|
||||
operator Matcher<T>() const {
|
||||
return Matcher<T>(new MatcherT<T, P1>(Param1));
|
||||
}
|
||||
|
||||
private:
|
||||
const P1 Param1;
|
||||
};
|
||||
|
||||
template <template <typename T, typename P1, typename P2> class MatcherT,
|
||||
typename P1, typename P2>
|
||||
class PolymorphicMatcherWithParam2 {
|
||||
public:
|
||||
PolymorphicMatcherWithParam2(const P1 &Param1, const P2 &Param2)
|
||||
: Param1(Param1), Param2(Param2) {}
|
||||
|
||||
template <typename T>
|
||||
operator Matcher<T>() const {
|
||||
return Matcher<T>(new MatcherT<T, P1, P2>(Param1, Param2));
|
||||
}
|
||||
|
||||
private:
|
||||
const P1 Param1;
|
||||
const P2 Param2;
|
||||
};
|
||||
|
||||
/// \brief Matches any instance of the given NodeType.
|
||||
///
|
||||
/// This is useful when a matcher syntactically requires a child matcher,
|
||||
/// but the context doesn't care. See for example: anything().
|
||||
///
|
||||
/// FIXME: Alternatively we could also create a IsAMatcher or something
|
||||
/// that checks that a dyn_cast is possible. This is purely needed for the
|
||||
/// difference between calling for example:
|
||||
/// record()
|
||||
/// and
|
||||
/// record(SomeMatcher)
|
||||
/// In the second case we need the correct type we were dyn_cast'ed to in order
|
||||
/// to get the right type for the inner matcher. In the first case we don't need
|
||||
/// that, but we use the type conversion anyway and insert a TrueMatcher.
|
||||
template <typename T>
|
||||
class TrueMatcher : public SingleNodeMatcherInterface<T> {
|
||||
public:
|
||||
virtual bool matchesNode(const T &Node) const {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief Provides a MatcherInterface<T> for a Matcher<To> that matches if T is
|
||||
/// dyn_cast'able into To and the given Matcher<To> matches on the dyn_cast'ed
|
||||
/// node.
|
||||
template <typename T, typename To>
|
||||
class DynCastMatcher : public MatcherInterface<T> {
|
||||
public:
|
||||
explicit DynCastMatcher(const Matcher<To> &InnerMatcher)
|
||||
: InnerMatcher(InnerMatcher) {}
|
||||
|
||||
virtual bool matches(const T &Node,
|
||||
ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
const To *InnerMatchValue = llvm::dyn_cast<To>(&Node);
|
||||
return InnerMatchValue != NULL &&
|
||||
InnerMatcher.matches(*InnerMatchValue, Finder, Builder);
|
||||
}
|
||||
|
||||
private:
|
||||
const Matcher<To> InnerMatcher;
|
||||
};
|
||||
|
||||
/// \brief Matcher<T> that wraps an inner Matcher<T> and binds the matched node
|
||||
/// to an ID if the inner matcher matches on the node.
|
||||
template <typename T>
|
||||
class IdMatcher : public MatcherInterface<T> {
|
||||
public:
|
||||
/// \brief Creates an IdMatcher that binds to 'ID' if 'InnerMatcher' matches
|
||||
/// the node.
|
||||
IdMatcher(StringRef ID, const Matcher<T> &InnerMatcher)
|
||||
: ID(ID), InnerMatcher(InnerMatcher) {}
|
||||
|
||||
virtual bool matches(const T &Node,
|
||||
ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
bool Result = InnerMatcher.matches(Node, Finder, Builder);
|
||||
if (Result) {
|
||||
Builder->setBinding(ID, &Node);
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
private:
|
||||
const std::string ID;
|
||||
const Matcher<T> InnerMatcher;
|
||||
};
|
||||
|
||||
/// \brief A Matcher that allows binding the node it matches to an id.
|
||||
///
|
||||
/// BindableMatcher provides a \a bind() method that allows binding the
|
||||
/// matched node to an id if the match was successful.
|
||||
template <typename T>
|
||||
class BindableMatcher : public Matcher<T> {
|
||||
public:
|
||||
BindableMatcher(MatcherInterface<T> *Implementation)
|
||||
: Matcher<T>(Implementation) {}
|
||||
|
||||
/// \brief Returns a matcher that will bind the matched node on a match.
|
||||
///
|
||||
/// 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));
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief Matches nodes of type T that have child nodes of type ChildT for
|
||||
/// which a specified child matcher matches.
|
||||
///
|
||||
/// ChildT must be an AST base type.
|
||||
template <typename T, typename ChildT>
|
||||
class HasMatcher : public MatcherInterface<T> {
|
||||
TOOLING_COMPILE_ASSERT(IsBaseType<ChildT>::value,
|
||||
has_only_accepts_base_type_matcher);
|
||||
public:
|
||||
explicit HasMatcher(const Matcher<ChildT> &ChildMatcher)
|
||||
: ChildMatcher(ChildMatcher) {}
|
||||
|
||||
virtual bool matches(const T &Node,
|
||||
ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
return Finder->matchesChildOf(
|
||||
Node, ChildMatcher, Builder,
|
||||
ASTMatchFinder::TK_IgnoreImplicitCastsAndParentheses,
|
||||
ASTMatchFinder::BK_First);
|
||||
}
|
||||
|
||||
private:
|
||||
const TypedBaseMatcher<ChildT> ChildMatcher;
|
||||
};
|
||||
|
||||
/// \brief Matches nodes of type T that have child nodes of type ChildT for
|
||||
/// which a specified child matcher matches. ChildT must be an AST base
|
||||
/// type.
|
||||
/// As opposed to the HasMatcher, the ForEachMatcher will produce a match
|
||||
/// for each child that matches.
|
||||
template <typename T, typename ChildT>
|
||||
class ForEachMatcher : public MatcherInterface<T> {
|
||||
TOOLING_COMPILE_ASSERT(IsBaseType<ChildT>::value,
|
||||
for_each_only_accepts_base_type_matcher);
|
||||
public:
|
||||
explicit ForEachMatcher(const Matcher<ChildT> &ChildMatcher)
|
||||
: ChildMatcher(ChildMatcher) {}
|
||||
|
||||
virtual bool matches(const T& Node,
|
||||
ASTMatchFinder* Finder,
|
||||
BoundNodesTreeBuilder* Builder) const {
|
||||
return Finder->matchesChildOf(
|
||||
Node, ChildMatcher, Builder,
|
||||
ASTMatchFinder::TK_IgnoreImplicitCastsAndParentheses,
|
||||
ASTMatchFinder::BK_All);
|
||||
}
|
||||
|
||||
private:
|
||||
const TypedBaseMatcher<ChildT> ChildMatcher;
|
||||
};
|
||||
|
||||
/// \brief Matches nodes of type T if the given Matcher<T> does not match.
|
||||
///
|
||||
/// Type argument MatcherT is required by PolymorphicMatcherWithParam1
|
||||
/// but not actually used. It will always be instantiated with a type
|
||||
/// convertible to Matcher<T>.
|
||||
template <typename T, typename MatcherT>
|
||||
class NotMatcher : public MatcherInterface<T> {
|
||||
public:
|
||||
explicit NotMatcher(const Matcher<T> &InnerMatcher)
|
||||
: InnerMatcher(InnerMatcher) {}
|
||||
|
||||
virtual bool matches(const T &Node,
|
||||
ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
return !InnerMatcher.matches(Node, Finder, Builder);
|
||||
}
|
||||
|
||||
private:
|
||||
const Matcher<T> InnerMatcher;
|
||||
};
|
||||
|
||||
/// \brief Matches nodes of type T for which both provided matchers match.
|
||||
///
|
||||
/// Type arguments MatcherT1 and MatcherT2 are required by
|
||||
/// PolymorphicMatcherWithParam2 but not actually used. They will
|
||||
/// always be instantiated with types convertible to Matcher<T>.
|
||||
template <typename T, typename MatcherT1, typename MatcherT2>
|
||||
class AllOfMatcher : public MatcherInterface<T> {
|
||||
public:
|
||||
AllOfMatcher(const Matcher<T> &InnerMatcher1, const Matcher<T> &InnerMatcher2)
|
||||
: InnerMatcher1(InnerMatcher1), InnerMatcher2(InnerMatcher2) {}
|
||||
|
||||
virtual bool matches(const T &Node,
|
||||
ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
return InnerMatcher1.matches(Node, Finder, Builder) &&
|
||||
InnerMatcher2.matches(Node, Finder, Builder);
|
||||
}
|
||||
|
||||
private:
|
||||
const Matcher<T> InnerMatcher1;
|
||||
const Matcher<T> InnerMatcher2;
|
||||
};
|
||||
|
||||
/// \brief Matches nodes of type T for which at least one of the two provided
|
||||
/// matchers matches.
|
||||
///
|
||||
/// Type arguments MatcherT1 and MatcherT2 are
|
||||
/// required by PolymorphicMatcherWithParam2 but not actually
|
||||
/// used. They will always be instantiated with types convertible to
|
||||
/// Matcher<T>.
|
||||
template <typename T, typename MatcherT1, typename MatcherT2>
|
||||
class AnyOfMatcher : public MatcherInterface<T> {
|
||||
public:
|
||||
AnyOfMatcher(const Matcher<T> &InnerMatcher1, const Matcher<T> &InnerMatcher2)
|
||||
: InnerMatcher1(InnerMatcher1), InnertMatcher2(InnerMatcher2) {}
|
||||
|
||||
virtual bool matches(const T &Node,
|
||||
ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
return InnerMatcher1.matches(Node, Finder, Builder) ||
|
||||
InnertMatcher2.matches(Node, Finder, Builder);
|
||||
}
|
||||
|
||||
private:
|
||||
const Matcher<T> InnerMatcher1;
|
||||
const Matcher<T> InnertMatcher2;
|
||||
};
|
||||
|
||||
/// \brief Creates a Matcher<T> that matches if
|
||||
/// T is dyn_cast'able into InnerT and all inner matchers match.
|
||||
///
|
||||
/// Returns BindableMatcher, as matchers that use dyn_cast have
|
||||
/// the same object both to match on and to run submatchers on,
|
||||
/// so there is no ambiguity with what gets bound.
|
||||
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));
|
||||
}
|
||||
|
||||
/// \brief Matches nodes of type T that have at least one descendant node of
|
||||
/// type DescendantT for which the given inner matcher matches.
|
||||
///
|
||||
/// DescendantT must be an AST base type.
|
||||
template <typename T, typename DescendantT>
|
||||
class HasDescendantMatcher : public MatcherInterface<T> {
|
||||
TOOLING_COMPILE_ASSERT(IsBaseType<DescendantT>::value,
|
||||
has_descendant_only_accepts_base_type_matcher);
|
||||
public:
|
||||
explicit HasDescendantMatcher(const Matcher<DescendantT> &DescendantMatcher)
|
||||
: DescendantMatcher(DescendantMatcher) {}
|
||||
|
||||
virtual bool matches(const T &Node,
|
||||
ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const {
|
||||
return Finder->matchesDescendantOf(
|
||||
Node, DescendantMatcher, Builder, ASTMatchFinder::BK_First);
|
||||
}
|
||||
|
||||
private:
|
||||
const TypedBaseMatcher<DescendantT> DescendantMatcher;
|
||||
};
|
||||
|
||||
/// \brief Matches nodes of type T that have at least one descendant node of
|
||||
/// type DescendantT for which the given inner matcher matches.
|
||||
///
|
||||
/// DescendantT must be an AST base type.
|
||||
/// As opposed to HasDescendantMatcher, ForEachDescendantMatcher will match
|
||||
/// for each descendant node that matches instead of only for the first.
|
||||
template <typename T, typename DescendantT>
|
||||
class ForEachDescendantMatcher : public MatcherInterface<T> {
|
||||
TOOLING_COMPILE_ASSERT(IsBaseType<DescendantT>::value,
|
||||
for_each_descendant_only_accepts_base_type_matcher);
|
||||
public:
|
||||
explicit ForEachDescendantMatcher(
|
||||
const Matcher<DescendantT>& DescendantMatcher)
|
||||
: DescendantMatcher(DescendantMatcher) {}
|
||||
|
||||
virtual bool matches(const T& Node,
|
||||
ASTMatchFinder* Finder,
|
||||
BoundNodesTreeBuilder* Builder) const {
|
||||
return Finder->matchesDescendantOf(Node, DescendantMatcher, Builder,
|
||||
ASTMatchFinder::BK_All);
|
||||
}
|
||||
|
||||
private:
|
||||
const TypedBaseMatcher<DescendantT> DescendantMatcher;
|
||||
};
|
||||
|
||||
/// \brief Matches on nodes that have a getValue() method if getValue() equals
|
||||
/// the value the ValueEqualsMatcher was constructed with.
|
||||
template <typename T, typename ValueT>
|
||||
class ValueEqualsMatcher : public SingleNodeMatcherInterface<T> {
|
||||
TOOLING_COMPILE_ASSERT((llvm::is_base_of<CharacterLiteral, T>::value ||
|
||||
llvm::is_base_of<CXXBoolLiteralExpr,
|
||||
T>::value ||
|
||||
llvm::is_base_of<FloatingLiteral, T>::value ||
|
||||
llvm::is_base_of<IntegerLiteral, T>::value),
|
||||
the_node_must_have_a_getValue_method);
|
||||
public:
|
||||
explicit ValueEqualsMatcher(const ValueT &ExpectedValue)
|
||||
: ExpectedValue(ExpectedValue) {}
|
||||
|
||||
virtual bool matchesNode(const T &Node) const {
|
||||
return Node.getValue() == ExpectedValue;
|
||||
}
|
||||
|
||||
private:
|
||||
const ValueT ExpectedValue;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class IsDefinitionMatcher : public SingleNodeMatcherInterface<T> {
|
||||
TOOLING_COMPILE_ASSERT(
|
||||
(llvm::is_base_of<TagDecl, T>::value) ||
|
||||
(llvm::is_base_of<VarDecl, T>::value) ||
|
||||
(llvm::is_base_of<FunctionDecl, T>::value),
|
||||
is_definition_requires_isThisDeclarationADefinition_method);
|
||||
public:
|
||||
virtual bool matchesNode(const T &Node) const {
|
||||
return Node.isThisDeclarationADefinition();
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief Matches on template instantiations for FunctionDecl, VarDecl or
|
||||
/// CXXRecordDecl nodes.
|
||||
template <typename T>
|
||||
class IsTemplateInstantiationMatcher : 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_ImplicitInstantiation ||
|
||||
Node.getTemplateSpecializationKind() ==
|
||||
TSK_ExplicitInstantiationDefinition);
|
||||
}
|
||||
};
|
||||
|
||||
class IsArrowMatcher : public SingleNodeMatcherInterface<MemberExpr> {
|
||||
public:
|
||||
virtual bool matchesNode(const MemberExpr &Node) const {
|
||||
return Node.isArrow();
|
||||
}
|
||||
};
|
||||
|
||||
class IsConstQualifiedMatcher
|
||||
: public SingleNodeMatcherInterface<QualType> {
|
||||
public:
|
||||
virtual bool matchesNode(const QualType& Node) const {
|
||||
return Node.isConstQualified();
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief A VariadicDynCastAllOfMatcher<SourceT, TargetT> object is a
|
||||
/// variadic functor that takes a number of Matcher<TargetT> and returns a
|
||||
/// Matcher<SourceT> that matches TargetT nodes that are matched by all of the
|
||||
/// given matchers, if SourceT can be dynamically casted into TargetT.
|
||||
///
|
||||
/// For example:
|
||||
/// const VariadicDynCastAllOfMatcher<
|
||||
/// Decl, CXXRecordDecl> record;
|
||||
/// Creates a functor record(...) that creates a Matcher<Decl> given
|
||||
/// a variable number of arguments of type Matcher<CXXRecordDecl>.
|
||||
/// The returned matcher matches if the given Decl can by dynamically
|
||||
/// casted to CXXRecordDecl and all given matchers match.
|
||||
template <typename SourceT, typename TargetT>
|
||||
class VariadicDynCastAllOfMatcher
|
||||
: public llvm::VariadicFunction<
|
||||
BindableMatcher<SourceT>, Matcher<TargetT>,
|
||||
makeDynCastAllOfComposite<SourceT, TargetT> > {
|
||||
public:
|
||||
VariadicDynCastAllOfMatcher() {}
|
||||
};
|
||||
|
||||
} // end namespace internal
|
||||
} // end namespace ast_matchers
|
||||
} // end namespace clang
|
||||
|
||||
#endif // LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_INTERNAL_H
|
||||
224
include/clang/ASTMatchers/ASTMatchersMacros.h
Normal file
224
include/clang/ASTMatchers/ASTMatchersMacros.h
Normal file
|
|
@ -0,0 +1,224 @@
|
|||
//===--- ASTMatchersMacros.h - Structural query framework -------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Defines macros that enable us to define new matchers in a single place.
|
||||
// Since a matcher is a function which returns a Matcher<T> object, where
|
||||
// T is the type of the actual implementation of the matcher, the macros allow
|
||||
// us to write matchers like functions and take care of the definition of the
|
||||
// class boilerplate.
|
||||
//
|
||||
// Note that when you define a matcher with an AST_MATCHER* macro, only the
|
||||
// function which creates the matcher goes into the current namespace - the
|
||||
// class that implements the actual matcher, which gets returned by the
|
||||
// generator function, is put into the 'internal' namespace. This allows us
|
||||
// to only have the functions (which is all the user cares about) in the
|
||||
// 'ast_matchers' namespace and hide the boilerplate.
|
||||
//
|
||||
// To define a matcher in user code, always put it into the clang::ast_matchers
|
||||
// namespace and refer to the internal types via the 'internal::':
|
||||
//
|
||||
// namespace clang {
|
||||
// namespace ast_matchers {
|
||||
// AST_MATCHER_P(MemberExpr, Member,
|
||||
// internal::Matcher<ValueDecl>, InnerMatcher) {
|
||||
// return InnerMatcher.matches(*Node.getMemberDecl(), Finder, Builder);
|
||||
// }
|
||||
// } // end namespace ast_matchers
|
||||
// } // end namespace clang
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_MACROS_H
|
||||
#define LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_MACROS_H
|
||||
|
||||
/// \brief AST_MATCHER(Type, DefineMatcher) { ... }
|
||||
/// defines a zero parameter function named DefineMatcher() that returns a
|
||||
/// Matcher<Type> object.
|
||||
///
|
||||
/// The code between the curly braces has access to the following variables:
|
||||
///
|
||||
/// Node: the AST node being matched; its type is Type.
|
||||
/// Finder: an ASTMatchFinder*.
|
||||
/// Builder: a BoundNodesTreeBuilder*.
|
||||
///
|
||||
/// The code should return true if 'Node' matches.
|
||||
#define AST_MATCHER(Type, DefineMatcher) \
|
||||
namespace internal { \
|
||||
class matcher_##DefineMatcher##Matcher \
|
||||
: public MatcherInterface<Type> { \
|
||||
public: \
|
||||
explicit matcher_##DefineMatcher##Matcher() {} \
|
||||
virtual bool matches( \
|
||||
const Type &Node, ASTMatchFinder *Finder, \
|
||||
BoundNodesTreeBuilder *Builder) const; \
|
||||
}; \
|
||||
} \
|
||||
inline internal::Matcher<Type> DefineMatcher() { \
|
||||
return internal::makeMatcher( \
|
||||
new internal::matcher_##DefineMatcher##Matcher()); \
|
||||
} \
|
||||
inline bool internal::matcher_##DefineMatcher##Matcher::matches( \
|
||||
const Type &Node, ASTMatchFinder *Finder, \
|
||||
BoundNodesTreeBuilder *Builder) const
|
||||
|
||||
/// \brief AST_MATCHER_P(Type, DefineMatcher, ParamType, Param) { ... }
|
||||
/// defines a single-parameter function named DefineMatcher() that returns a
|
||||
/// Matcher<Type> object.
|
||||
///
|
||||
/// The code between the curly braces has access to the following variables:
|
||||
///
|
||||
/// Node: the AST node being matched; its type is Type.
|
||||
/// Param: the parameter passed to the function; its type
|
||||
/// is ParamType.
|
||||
/// Finder: an ASTMatchFinder*.
|
||||
/// Builder: a BoundNodesTreeBuilder*.
|
||||
///
|
||||
/// The code should return true if 'Node' matches.
|
||||
#define AST_MATCHER_P(Type, DefineMatcher, ParamType, Param) \
|
||||
namespace internal { \
|
||||
class matcher_##DefineMatcher##Matcher \
|
||||
: public MatcherInterface<Type> { \
|
||||
public: \
|
||||
explicit matcher_##DefineMatcher##Matcher( \
|
||||
const ParamType &A##Param) : Param(A##Param) {} \
|
||||
virtual bool matches( \
|
||||
const Type &Node, ASTMatchFinder *Finder, \
|
||||
BoundNodesTreeBuilder *Builder) const; \
|
||||
private: \
|
||||
const ParamType Param; \
|
||||
}; \
|
||||
} \
|
||||
inline internal::Matcher<Type> DefineMatcher(const ParamType &Param) { \
|
||||
return internal::makeMatcher( \
|
||||
new internal::matcher_##DefineMatcher##Matcher(Param)); \
|
||||
} \
|
||||
inline bool internal::matcher_##DefineMatcher##Matcher::matches( \
|
||||
const Type &Node, ASTMatchFinder *Finder, \
|
||||
BoundNodesTreeBuilder *Builder) const
|
||||
|
||||
/// \brief AST_MATCHER_P2(
|
||||
/// Type, DefineMatcher, ParamType1, Param1, ParamType2, Param2) { ... }
|
||||
/// defines a two-parameter function named DefineMatcher() that returns a
|
||||
/// Matcher<Type> object.
|
||||
///
|
||||
/// The code between the curly braces has access to the following variables:
|
||||
///
|
||||
/// Node: the AST node being matched; its type is Type.
|
||||
/// Param1, Param2: the parameters passed to the function; their types
|
||||
/// are ParamType1 and ParamType2.
|
||||
/// Finder: an ASTMatchFinder*.
|
||||
/// Builder: a BoundNodesTreeBuilder*.
|
||||
///
|
||||
/// The code should return true if 'Node' matches.
|
||||
#define AST_MATCHER_P2( \
|
||||
Type, DefineMatcher, ParamType1, Param1, ParamType2, Param2) \
|
||||
namespace internal { \
|
||||
class matcher_##DefineMatcher##Matcher \
|
||||
: public MatcherInterface<Type> { \
|
||||
public: \
|
||||
matcher_##DefineMatcher##Matcher( \
|
||||
const ParamType1 &A##Param1, const ParamType2 &A##Param2) \
|
||||
: Param1(A##Param1), Param2(A##Param2) {} \
|
||||
virtual bool matches( \
|
||||
const Type &Node, ASTMatchFinder *Finder, \
|
||||
BoundNodesTreeBuilder *Builder) const; \
|
||||
private: \
|
||||
const ParamType1 Param1; \
|
||||
const ParamType2 Param2; \
|
||||
}; \
|
||||
} \
|
||||
inline internal::Matcher<Type> DefineMatcher( \
|
||||
const ParamType1 &Param1, const ParamType2 &Param2) { \
|
||||
return internal::makeMatcher( \
|
||||
new internal::matcher_##DefineMatcher##Matcher( \
|
||||
Param1, Param2)); \
|
||||
} \
|
||||
inline bool internal::matcher_##DefineMatcher##Matcher::matches( \
|
||||
const Type &Node, ASTMatchFinder *Finder, \
|
||||
BoundNodesTreeBuilder *Builder) const
|
||||
|
||||
/// \brief AST_POLYMORPHIC_MATCHER_P(DefineMatcher, ParamType, Param) { ... }
|
||||
/// defines a single-parameter function named DefineMatcher() that is
|
||||
/// polymorphic in the return type.
|
||||
///
|
||||
/// The variables are the same as for
|
||||
/// AST_MATCHER_P, with the addition of NodeType, which specifies the node type
|
||||
/// of the matcher Matcher<NodeType> returned by the function matcher().
|
||||
///
|
||||
/// FIXME: Pull out common code with above macro?
|
||||
#define AST_POLYMORPHIC_MATCHER_P(DefineMatcher, ParamType, Param) \
|
||||
namespace internal { \
|
||||
template <typename NodeType, typename ParamT> \
|
||||
class matcher_##DefineMatcher##Matcher \
|
||||
: public MatcherInterface<NodeType> { \
|
||||
public: \
|
||||
explicit matcher_##DefineMatcher##Matcher( \
|
||||
const ParamType &A##Param) : Param(A##Param) {} \
|
||||
virtual bool matches( \
|
||||
const NodeType &Node, ASTMatchFinder *Finder, \
|
||||
BoundNodesTreeBuilder *Builder) const; \
|
||||
private: \
|
||||
const ParamType Param; \
|
||||
}; \
|
||||
} \
|
||||
inline internal::PolymorphicMatcherWithParam1< \
|
||||
internal::matcher_##DefineMatcher##Matcher, \
|
||||
ParamType > \
|
||||
DefineMatcher(const ParamType &Param) { \
|
||||
return internal::PolymorphicMatcherWithParam1< \
|
||||
internal::matcher_##DefineMatcher##Matcher, \
|
||||
ParamType >(Param); \
|
||||
} \
|
||||
template <typename NodeType, typename ParamT> \
|
||||
bool internal::matcher_##DefineMatcher##Matcher<NodeType, ParamT>::matches( \
|
||||
const NodeType &Node, ASTMatchFinder *Finder, \
|
||||
BoundNodesTreeBuilder *Builder) const
|
||||
|
||||
/// \brief AST_POLYMORPHIC_MATCHER_P2(
|
||||
/// DefineMatcher, ParamType1, Param1, ParamType2, Param2) { ... }
|
||||
/// defines a two-parameter function named matcher() that is polymorphic in
|
||||
/// the return type.
|
||||
///
|
||||
/// The variables are the same as for AST_MATCHER_P2, with the
|
||||
/// addition of NodeType, which specifies the node type of the matcher
|
||||
/// Matcher<NodeType> returned by the function DefineMatcher().
|
||||
#define AST_POLYMORPHIC_MATCHER_P2( \
|
||||
DefineMatcher, ParamType1, Param1, ParamType2, Param2) \
|
||||
namespace internal { \
|
||||
template <typename NodeType, typename ParamT1, typename ParamT2> \
|
||||
class matcher_##DefineMatcher##Matcher \
|
||||
: public MatcherInterface<NodeType> { \
|
||||
public: \
|
||||
matcher_##DefineMatcher##Matcher( \
|
||||
const ParamType1 &A##Param1, const ParamType2 &A##Param2) \
|
||||
: Param1(A##Param1), Param2(A##Param2) {} \
|
||||
virtual bool matches( \
|
||||
const NodeType &Node, ASTMatchFinder *Finder, \
|
||||
BoundNodesTreeBuilder *Builder) const; \
|
||||
private: \
|
||||
const ParamType1 Param1; \
|
||||
const ParamType2 Param2; \
|
||||
}; \
|
||||
} \
|
||||
inline internal::PolymorphicMatcherWithParam2< \
|
||||
internal::matcher_##DefineMatcher##Matcher, \
|
||||
ParamType1, ParamType2 > \
|
||||
DefineMatcher(const ParamType1 &Param1, const ParamType2 &Param2) { \
|
||||
return internal::PolymorphicMatcherWithParam2< \
|
||||
internal::matcher_##DefineMatcher##Matcher, \
|
||||
ParamType1, ParamType2 >( \
|
||||
Param1, Param2); \
|
||||
} \
|
||||
template <typename NodeType, typename ParamT1, typename ParamT2> \
|
||||
bool internal::matcher_##DefineMatcher##Matcher< \
|
||||
NodeType, ParamT1, ParamT2>::matches( \
|
||||
const NodeType &Node, ASTMatchFinder *Finder, \
|
||||
BoundNodesTreeBuilder *Builder) const
|
||||
|
||||
#endif // LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_MACROS_H
|
||||
|
|
@ -175,6 +175,7 @@ public:
|
|||
switch (kind) {
|
||||
case PrintErrno:
|
||||
assert(IsPrintf);
|
||||
return false;
|
||||
case PercentArg:
|
||||
return false;
|
||||
default:
|
||||
|
|
@ -200,7 +201,7 @@ protected:
|
|||
Kind kind;
|
||||
};
|
||||
|
||||
class ArgTypeResult {
|
||||
class ArgType {
|
||||
public:
|
||||
enum Kind { UnknownTy, InvalidTy, SpecificTy, ObjCPointerTy, CPointerTy,
|
||||
AnyCharTy, CStrTy, WCStrTy, WIntTy };
|
||||
|
|
@ -208,26 +209,26 @@ private:
|
|||
const Kind K;
|
||||
QualType T;
|
||||
const char *Name;
|
||||
ArgTypeResult(bool) : K(InvalidTy), Name(0) {}
|
||||
bool Ptr;
|
||||
public:
|
||||
ArgTypeResult(Kind k = UnknownTy) : K(k), Name(0) {}
|
||||
ArgTypeResult(Kind k, const char *n) : K(k), Name(n) {}
|
||||
ArgTypeResult(QualType t) : K(SpecificTy), T(t), Name(0) {}
|
||||
ArgTypeResult(QualType t, const char *n) : K(SpecificTy), T(t), Name(n) {}
|
||||
ArgTypeResult(CanQualType t) : K(SpecificTy), T(t), Name(0) {}
|
||||
|
||||
static ArgTypeResult Invalid() { return ArgTypeResult(true); }
|
||||
ArgType(Kind k = UnknownTy, const char *n = 0) : K(k), Name(n), Ptr(false) {}
|
||||
ArgType(QualType t, const char *n = 0)
|
||||
: K(SpecificTy), T(t), Name(n), Ptr(false) {}
|
||||
ArgType(CanQualType t) : K(SpecificTy), T(t), Name(0), Ptr(false) {}
|
||||
|
||||
static ArgType Invalid() { return ArgType(InvalidTy); }
|
||||
bool isValid() const { return K != InvalidTy; }
|
||||
|
||||
const QualType *getSpecificType() const {
|
||||
return K == SpecificTy ? &T : 0;
|
||||
/// Create an ArgType which corresponds to the type pointer to A.
|
||||
static ArgType PtrTo(const ArgType& A) {
|
||||
assert(A.K >= InvalidTy && "ArgType cannot be pointer to invalid/unknown");
|
||||
ArgType Res = A;
|
||||
Res.Ptr = true;
|
||||
return Res;
|
||||
}
|
||||
|
||||
bool matchesType(ASTContext &C, QualType argTy) const;
|
||||
|
||||
bool matchesAnyObjCObjectRef() const { return K == ObjCPointerTy; }
|
||||
|
||||
QualType getRepresentativeType(ASTContext &C) const;
|
||||
|
||||
std::string getRepresentativeTypeName(ASTContext &C) const;
|
||||
|
|
@ -278,7 +279,7 @@ public:
|
|||
return length + UsesDotPrefix;
|
||||
}
|
||||
|
||||
ArgTypeResult getArgType(ASTContext &Ctx) const;
|
||||
ArgType getArgType(ASTContext &Ctx) const;
|
||||
|
||||
void toString(raw_ostream &os) const;
|
||||
|
||||
|
|
@ -354,6 +355,10 @@ public:
|
|||
bool hasStandardConversionSpecifier(const LangOptions &LangOpt) const;
|
||||
|
||||
bool hasStandardLengthConversionCombination() const;
|
||||
|
||||
/// For a TypedefType QT, if it is a named integer type such as size_t,
|
||||
/// assign the appropriate value to LM and return true.
|
||||
static bool namedTypeToLengthModifier(QualType QT, LengthModifier &LM);
|
||||
};
|
||||
|
||||
} // end analyze_format_string namespace
|
||||
|
|
@ -387,7 +392,7 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
using analyze_format_string::ArgTypeResult;
|
||||
using analyze_format_string::ArgType;
|
||||
using analyze_format_string::LengthModifier;
|
||||
using analyze_format_string::OptionalAmount;
|
||||
using analyze_format_string::OptionalFlag;
|
||||
|
|
@ -462,7 +467,7 @@ public:
|
|||
/// will return null if the format specifier does not have
|
||||
/// a matching data argument or the matching argument matches
|
||||
/// more than one type.
|
||||
ArgTypeResult getArgType(ASTContext &Ctx, bool IsObjCLiteral) const;
|
||||
ArgType getArgType(ASTContext &Ctx, bool IsObjCLiteral) const;
|
||||
|
||||
const OptionalFlag &hasThousandsGrouping() const {
|
||||
return HasThousandsGrouping;
|
||||
|
|
@ -516,35 +521,11 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
using analyze_format_string::ArgTypeResult;
|
||||
using analyze_format_string::ArgType;
|
||||
using analyze_format_string::LengthModifier;
|
||||
using analyze_format_string::OptionalAmount;
|
||||
using analyze_format_string::OptionalFlag;
|
||||
|
||||
class ScanfArgTypeResult : public ArgTypeResult {
|
||||
public:
|
||||
enum Kind { UnknownTy, InvalidTy, CStrTy, WCStrTy, PtrToArgTypeResultTy };
|
||||
private:
|
||||
Kind K;
|
||||
ArgTypeResult A;
|
||||
const char *Name;
|
||||
QualType getRepresentativeType(ASTContext &C) const;
|
||||
public:
|
||||
ScanfArgTypeResult(Kind k = UnknownTy, const char* n = 0) : K(k), Name(n) {}
|
||||
ScanfArgTypeResult(ArgTypeResult a, const char *n = 0)
|
||||
: K(PtrToArgTypeResultTy), A(a), Name(n) {
|
||||
assert(A.isValid());
|
||||
}
|
||||
|
||||
static ScanfArgTypeResult Invalid() { return ScanfArgTypeResult(InvalidTy); }
|
||||
|
||||
bool isValid() const { return K != InvalidTy; }
|
||||
|
||||
bool matchesType(ASTContext& C, QualType argTy) const;
|
||||
|
||||
std::string getRepresentativeTypeName(ASTContext& C) const;
|
||||
};
|
||||
|
||||
class ScanfSpecifier : public analyze_format_string::FormatSpecifier {
|
||||
OptionalFlag SuppressAssignment; // '*'
|
||||
public:
|
||||
|
|
@ -573,7 +554,7 @@ public:
|
|||
return CS.consumesDataArgument() && !SuppressAssignment;
|
||||
}
|
||||
|
||||
ScanfArgTypeResult getArgType(ASTContext &Ctx) const;
|
||||
ArgType getArgType(ASTContext &Ctx) const;
|
||||
|
||||
bool fixType(QualType QT, const LangOptions &LangOpt, ASTContext &Ctx);
|
||||
|
||||
|
|
|
|||
|
|
@ -60,7 +60,8 @@ enum AccessKind {
|
|||
enum LockErrorKind {
|
||||
LEK_LockedSomeLoopIterations,
|
||||
LEK_LockedSomePredecessors,
|
||||
LEK_LockedAtEndOfFunction
|
||||
LEK_LockedAtEndOfFunction,
|
||||
LEK_NotLockedAtEndOfFunction
|
||||
};
|
||||
|
||||
/// Handler class for thread safety warnings.
|
||||
|
|
@ -123,11 +124,11 @@ public:
|
|||
|
||||
/// Warn when a protected operation occurs while the specific mutex protecting
|
||||
/// the operation is not locked.
|
||||
/// \param LockName -- A StringRef name for the lock expression, to be printed
|
||||
/// in the error message.
|
||||
/// \param D -- The decl for the protected variable or function
|
||||
/// \param POK -- The kind of protected operation (e.g. variable access)
|
||||
/// \param AK -- The kind of access (i.e. read or write) that occurred
|
||||
/// \param LockName -- A StringRef name for the lock expression, to be printed
|
||||
/// in the error message.
|
||||
/// \param LK -- The kind of access (i.e. read or write) that occurred
|
||||
/// \param Loc -- The location of the protected operation.
|
||||
virtual void handleMutexNotHeld(const NamedDecl *D,
|
||||
ProtectedOperationKind POK, Name LockName,
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@
|
|||
#ifndef LLVM_CLANG_UNINIT_VALS_H
|
||||
#define LLVM_CLANG_UNINIT_VALS_H
|
||||
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
class AnalysisDeclContext;
|
||||
|
|
@ -23,15 +25,67 @@ class DeclContext;
|
|||
class Expr;
|
||||
class VarDecl;
|
||||
|
||||
/// A use of a variable, which might be uninitialized.
|
||||
class UninitUse {
|
||||
public:
|
||||
struct Branch {
|
||||
const Stmt *Terminator;
|
||||
unsigned Output;
|
||||
};
|
||||
|
||||
private:
|
||||
/// The expression which uses this variable.
|
||||
const Expr *User;
|
||||
|
||||
/// Does this use always see an uninitialized value?
|
||||
bool AlwaysUninit;
|
||||
|
||||
/// This use is always uninitialized if it occurs after any of these branches
|
||||
/// is taken.
|
||||
llvm::SmallVector<Branch, 2> UninitBranches;
|
||||
|
||||
public:
|
||||
UninitUse(const Expr *User, bool AlwaysUninit) :
|
||||
User(User), AlwaysUninit(AlwaysUninit) {}
|
||||
|
||||
void addUninitBranch(Branch B) {
|
||||
UninitBranches.push_back(B);
|
||||
}
|
||||
|
||||
/// Get the expression containing the uninitialized use.
|
||||
const Expr *getUser() const { return User; }
|
||||
|
||||
/// The kind of uninitialized use.
|
||||
enum Kind {
|
||||
/// The use might be uninitialized.
|
||||
Maybe,
|
||||
/// The use is uninitialized whenever a certain branch is taken.
|
||||
Sometimes,
|
||||
/// The use is always uninitialized.
|
||||
Always
|
||||
};
|
||||
|
||||
/// Get the kind of uninitialized use.
|
||||
Kind getKind() const {
|
||||
return AlwaysUninit ? Always :
|
||||
!branch_empty() ? Sometimes : Maybe;
|
||||
}
|
||||
|
||||
typedef llvm::SmallVectorImpl<Branch>::const_iterator branch_iterator;
|
||||
/// Branches which inevitably result in the variable being used uninitialized.
|
||||
branch_iterator branch_begin() const { return UninitBranches.begin(); }
|
||||
branch_iterator branch_end() const { return UninitBranches.end(); }
|
||||
bool branch_empty() const { return UninitBranches.empty(); }
|
||||
};
|
||||
|
||||
class UninitVariablesHandler {
|
||||
public:
|
||||
UninitVariablesHandler() {}
|
||||
virtual ~UninitVariablesHandler();
|
||||
|
||||
/// Called when the uninitialized variable is used at the given expression.
|
||||
virtual void handleUseOfUninitVariable(const Expr *ex,
|
||||
const VarDecl *vd,
|
||||
bool isAlwaysUninit) {}
|
||||
virtual void handleUseOfUninitVariable(const VarDecl *vd,
|
||||
const UninitUse &use) {}
|
||||
|
||||
/// Called when the uninitialized variable analysis detects the
|
||||
/// idiom 'int x = x'. All other uses of 'x' within the initializer
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ class PseudoConstantAnalysis;
|
|||
class ImplicitParamDecl;
|
||||
class LocationContextManager;
|
||||
class StackFrameContext;
|
||||
class BlockInvocationContext;
|
||||
class AnalysisDeclContextManager;
|
||||
class LocationContext;
|
||||
|
||||
|
|
@ -73,9 +74,6 @@ class AnalysisDeclContext {
|
|||
|
||||
const Decl *D;
|
||||
|
||||
// TranslationUnit is NULL if we don't have multiple translation units.
|
||||
idx::TranslationUnit *TU;
|
||||
|
||||
OwningPtr<CFG> cfg, completeCFG;
|
||||
OwningPtr<CFGStmtMap> cfgStmtMap;
|
||||
|
||||
|
|
@ -98,12 +96,10 @@ class AnalysisDeclContext {
|
|||
|
||||
public:
|
||||
AnalysisDeclContext(AnalysisDeclContextManager *Mgr,
|
||||
const Decl *D,
|
||||
idx::TranslationUnit *TU);
|
||||
const Decl *D);
|
||||
|
||||
AnalysisDeclContext(AnalysisDeclContextManager *Mgr,
|
||||
const Decl *D,
|
||||
idx::TranslationUnit *TU,
|
||||
const CFG::BuildOptions &BuildOptions);
|
||||
|
||||
~AnalysisDeclContext();
|
||||
|
|
@ -111,8 +107,6 @@ public:
|
|||
ASTContext &getASTContext() { return D->getASTContext(); }
|
||||
const Decl *getDecl() const { return D; }
|
||||
|
||||
idx::TranslationUnit *getTranslationUnit() const { return TU; }
|
||||
|
||||
/// Return the build options used to construct the CFG.
|
||||
CFG::BuildOptions &getCFGBuildOptions() {
|
||||
return cfgBuildOptions;
|
||||
|
|
@ -169,6 +163,11 @@ public:
|
|||
const Stmt *S,
|
||||
const CFGBlock *Blk,
|
||||
unsigned Idx);
|
||||
|
||||
const BlockInvocationContext *
|
||||
getBlockInvocationContext(const LocationContext *parent,
|
||||
const BlockDecl *BD,
|
||||
const void *ContextData);
|
||||
|
||||
/// Return the specified analysis object, lazily running the analysis if
|
||||
/// necessary. Return NULL if the analysis could not run.
|
||||
|
|
@ -212,10 +211,6 @@ public:
|
|||
|
||||
AnalysisDeclContext *getAnalysisDeclContext() const { return Ctx; }
|
||||
|
||||
idx::TranslationUnit *getTranslationUnit() const {
|
||||
return Ctx->getTranslationUnit();
|
||||
}
|
||||
|
||||
const LocationContext *getParent() const { return Parent; }
|
||||
|
||||
bool isParentOf(const LocationContext *LC) const;
|
||||
|
|
@ -238,8 +233,6 @@ public:
|
|||
}
|
||||
|
||||
const StackFrameContext *getCurrentStackFrame() const;
|
||||
const StackFrameContext *
|
||||
getStackFrameForDeclContext(const DeclContext *DC) const;
|
||||
|
||||
virtual void Profile(llvm::FoldingSetNodeID &ID) = 0;
|
||||
|
||||
|
|
@ -318,27 +311,32 @@ public:
|
|||
};
|
||||
|
||||
class BlockInvocationContext : public LocationContext {
|
||||
// FIXME: Add back context-sensivity (we don't want libAnalysis to know
|
||||
// about MemRegion).
|
||||
const BlockDecl *BD;
|
||||
|
||||
// FIXME: Come up with a more type-safe way to model context-sensitivity.
|
||||
const void *ContextData;
|
||||
|
||||
friend class LocationContextManager;
|
||||
|
||||
BlockInvocationContext(AnalysisDeclContext *ctx,
|
||||
const LocationContext *parent,
|
||||
const BlockDecl *bd)
|
||||
: LocationContext(Block, ctx, parent), BD(bd) {}
|
||||
const BlockDecl *bd, const void *contextData)
|
||||
: LocationContext(Block, ctx, parent), BD(bd), ContextData(contextData) {}
|
||||
|
||||
public:
|
||||
~BlockInvocationContext() {}
|
||||
|
||||
const BlockDecl *getBlockDecl() const { return BD; }
|
||||
|
||||
const void *getContextData() const { return ContextData; }
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID);
|
||||
|
||||
static void Profile(llvm::FoldingSetNodeID &ID, AnalysisDeclContext *ctx,
|
||||
const LocationContext *parent, const BlockDecl *bd) {
|
||||
const LocationContext *parent, const BlockDecl *bd,
|
||||
const void *contextData) {
|
||||
ProfileCommon(ID, Block, ctx, parent, bd);
|
||||
ID.AddPointer(contextData);
|
||||
}
|
||||
|
||||
static bool classof(const LocationContext *Ctx) {
|
||||
|
|
@ -359,6 +357,12 @@ public:
|
|||
const ScopeContext *getScope(AnalysisDeclContext *ctx,
|
||||
const LocationContext *parent,
|
||||
const Stmt *s);
|
||||
|
||||
const BlockInvocationContext *
|
||||
getBlockInvocationContext(AnalysisDeclContext *ctx,
|
||||
const LocationContext *parent,
|
||||
const BlockDecl *BD,
|
||||
const void *ContextData);
|
||||
|
||||
/// Discard all previously created LocationContext objects.
|
||||
void clear();
|
||||
|
|
@ -383,7 +387,7 @@ public:
|
|||
|
||||
~AnalysisDeclContextManager();
|
||||
|
||||
AnalysisDeclContext *getContext(const Decl *D, idx::TranslationUnit *TU = 0);
|
||||
AnalysisDeclContext *getContext(const Decl *D);
|
||||
|
||||
bool getUseUnoptimizedCFG() const {
|
||||
return !cfgBuildOptions.PruneTriviallyFalseEdges;
|
||||
|
|
@ -402,9 +406,8 @@ public:
|
|||
}
|
||||
|
||||
// Get the top level stack frame.
|
||||
const StackFrameContext *getStackFrame(Decl const *D,
|
||||
idx::TranslationUnit *TU) {
|
||||
return LocContexts.getStackFrame(getContext(D, TU), 0, 0, 0, 0);
|
||||
const StackFrameContext *getStackFrame(const Decl *D) {
|
||||
return LocContexts.getStackFrame(getContext(D), 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
// Get a stack frame with parent.
|
||||
|
|
@ -416,7 +419,6 @@ public:
|
|||
return LocContexts.getStackFrame(getContext(D), Parent, S, Blk, Idx);
|
||||
}
|
||||
|
||||
|
||||
/// Discard all previously created AnalysisDeclContexts.
|
||||
void clear();
|
||||
|
||||
|
|
|
|||
|
|
@ -21,10 +21,10 @@
|
|||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/BitVector.h"
|
||||
#include "clang/AST/Stmt.h"
|
||||
#include "clang/Analysis/Support/BumpVector.h"
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include <bitset>
|
||||
#include <cassert>
|
||||
#include <iterator>
|
||||
|
||||
|
|
@ -277,6 +277,7 @@ class CFGBlock {
|
|||
typedef std::reverse_iterator<ImplTy::const_iterator> const_iterator;
|
||||
typedef ImplTy::iterator reverse_iterator;
|
||||
typedef ImplTy::const_iterator const_reverse_iterator;
|
||||
typedef ImplTy::const_reference const_reference;
|
||||
|
||||
void push_back(CFGElement e, BumpVectorContext &C) { Impl.push_back(e, C); }
|
||||
reverse_iterator insert(reverse_iterator I, size_t Cnt, CFGElement E,
|
||||
|
|
@ -284,8 +285,8 @@ class CFGBlock {
|
|||
return Impl.insert(I, Cnt, E, C);
|
||||
}
|
||||
|
||||
CFGElement front() const { return Impl.back(); }
|
||||
CFGElement back() const { return Impl.front(); }
|
||||
const_reference front() const { return Impl.back(); }
|
||||
const_reference back() const { return Impl.front(); }
|
||||
|
||||
iterator begin() { return Impl.rbegin(); }
|
||||
iterator end() { return Impl.rend(); }
|
||||
|
|
@ -558,7 +559,7 @@ public:
|
|||
//===--------------------------------------------------------------------===//
|
||||
|
||||
class BuildOptions {
|
||||
llvm::BitVector alwaysAddMask;
|
||||
std::bitset<Stmt::lastStmtConstant> alwaysAddMask;
|
||||
public:
|
||||
typedef llvm::DenseMap<const Stmt *, const CFGBlock*> ForcedBlkExprs;
|
||||
ForcedBlkExprs **forcedBlkExprs;
|
||||
|
|
@ -583,8 +584,7 @@ public:
|
|||
}
|
||||
|
||||
BuildOptions()
|
||||
: alwaysAddMask(Stmt::lastStmtConstant, false)
|
||||
,forcedBlkExprs(0), PruneTriviallyFalseEdges(true)
|
||||
: forcedBlkExprs(0), PruneTriviallyFalseEdges(true)
|
||||
,AddEHEdges(false)
|
||||
,AddInitializers(false)
|
||||
,AddImplicitDtors(false) {}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@
|
|||
namespace clang {
|
||||
class CallGraphNode;
|
||||
|
||||
/// \class The AST-based call graph.
|
||||
/// \brief The AST-based call graph.
|
||||
///
|
||||
/// The call graph extends itself with the given declarations by implementing
|
||||
/// the recursive AST visitor, which constructs the graph by visiting the given
|
||||
|
|
@ -102,7 +102,8 @@ public:
|
|||
void dump() const;
|
||||
void viewGraph() const;
|
||||
|
||||
/// Part of recursive declaration visitation.
|
||||
/// Part of recursive declaration visitation. We recursively visit all the
|
||||
/// Declarations to collect the root functions.
|
||||
bool VisitFunctionDecl(FunctionDecl *FD) {
|
||||
// We skip function template definitions, as their semantics is
|
||||
// only determined when they are instantiated.
|
||||
|
|
@ -121,6 +122,11 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
// We are only collecting the declarations, so do not step into the bodies.
|
||||
bool TraverseStmt(Stmt *S) { return true; }
|
||||
|
||||
bool shouldWalkTypesOfTypeLocs() const { return false; }
|
||||
|
||||
private:
|
||||
/// \brief Add the given declaration to the call graph.
|
||||
void addNodeForDecl(Decl *D, bool IsGlobal);
|
||||
|
|
|
|||
|
|
@ -40,30 +40,36 @@ public:
|
|||
BlockEntranceKind,
|
||||
BlockExitKind,
|
||||
PreStmtKind,
|
||||
PreStmtPurgeDeadSymbolsKind,
|
||||
PostStmtPurgeDeadSymbolsKind,
|
||||
PostStmtKind,
|
||||
PreLoadKind,
|
||||
PostLoadKind,
|
||||
PreStoreKind,
|
||||
PostStoreKind,
|
||||
PostPurgeDeadSymbolsKind,
|
||||
PostConditionKind,
|
||||
PostLValueKind,
|
||||
MinPostStmtKind = PostStmtKind,
|
||||
MaxPostStmtKind = PostLValueKind,
|
||||
PostInitializerKind,
|
||||
CallEnterKind,
|
||||
CallExitKind,
|
||||
MinPostStmtKind = PostStmtKind,
|
||||
MaxPostStmtKind = CallExitKind,
|
||||
CallExitBeginKind,
|
||||
CallExitEndKind,
|
||||
PreImplicitCallKind,
|
||||
PostImplicitCallKind,
|
||||
MinImplicitCallKind = PreImplicitCallKind,
|
||||
MaxImplicitCallKind = PostImplicitCallKind,
|
||||
EpsilonKind};
|
||||
|
||||
private:
|
||||
llvm::PointerIntPair<const void *, 2, unsigned> Data1;
|
||||
const void *Data1;
|
||||
llvm::PointerIntPair<const void *, 2, unsigned> Data2;
|
||||
|
||||
// The LocationContext could be NULL to allow ProgramPoint to be used in
|
||||
// context insensitive analysis.
|
||||
llvm::PointerIntPair<const LocationContext *, 2, unsigned> L;
|
||||
|
||||
const ProgramPointTag *Tag;
|
||||
llvm::PointerIntPair<const ProgramPointTag *, 2, unsigned> Tag;
|
||||
|
||||
ProgramPoint();
|
||||
|
||||
|
|
@ -72,10 +78,10 @@ protected:
|
|||
Kind k,
|
||||
const LocationContext *l,
|
||||
const ProgramPointTag *tag = 0)
|
||||
: Data1(P, ((unsigned) k) & 0x3),
|
||||
Data2(0, (((unsigned) k) >> 2) & 0x3),
|
||||
L(l, (((unsigned) k) >> 4) & 0x3),
|
||||
Tag(tag) {
|
||||
: Data1(P),
|
||||
Data2(0, (((unsigned) k) >> 0) & 0x3),
|
||||
L(l, (((unsigned) k) >> 2) & 0x3),
|
||||
Tag(tag, (((unsigned) k) >> 4) & 0x3) {
|
||||
assert(getKind() == k);
|
||||
assert(getLocationContext() == l);
|
||||
assert(getData1() == P);
|
||||
|
|
@ -86,13 +92,13 @@ protected:
|
|||
Kind k,
|
||||
const LocationContext *l,
|
||||
const ProgramPointTag *tag = 0)
|
||||
: Data1(P1, ((unsigned) k) & 0x3),
|
||||
Data2(P2, (((unsigned) k) >> 2) & 0x3),
|
||||
L(l, (((unsigned) k) >> 4) & 0x3),
|
||||
Tag(tag) {}
|
||||
: Data1(P1),
|
||||
Data2(P2, (((unsigned) k) >> 0) & 0x3),
|
||||
L(l, (((unsigned) k) >> 2) & 0x3),
|
||||
Tag(tag, (((unsigned) k) >> 4) & 0x3) {}
|
||||
|
||||
protected:
|
||||
const void *getData1() const { return Data1.getPointer(); }
|
||||
const void *getData1() const { return Data1; }
|
||||
const void *getData2() const { return Data2.getPointer(); }
|
||||
void setData2(const void *d) { Data2.setPointer(d); }
|
||||
|
||||
|
|
@ -105,15 +111,23 @@ public:
|
|||
}
|
||||
|
||||
Kind getKind() const {
|
||||
unsigned x = L.getInt();
|
||||
unsigned x = Tag.getInt();
|
||||
x <<= 2;
|
||||
x |= L.getInt();
|
||||
x <<= 2;
|
||||
x |= Data2.getInt();
|
||||
x <<= 2;
|
||||
x |= Data1.getInt();
|
||||
return (Kind) x;
|
||||
}
|
||||
|
||||
const ProgramPointTag *getTag() const { return Tag; }
|
||||
/// \brief Is this a program point corresponding to purge/removal of dead
|
||||
/// symbols and bindings.
|
||||
bool isPurgeKind() {
|
||||
Kind K = getKind();
|
||||
return (K == PostStmtPurgeDeadSymbolsKind ||
|
||||
K == PreStmtPurgeDeadSymbolsKind);
|
||||
}
|
||||
|
||||
const ProgramPointTag *getTag() const { return Tag.getPointer(); }
|
||||
|
||||
const LocationContext *getLocationContext() const {
|
||||
return L.getPointer();
|
||||
|
|
@ -147,7 +161,7 @@ public:
|
|||
ID.AddPointer(getData1());
|
||||
ID.AddPointer(getData2());
|
||||
ID.AddPointer(getLocationContext());
|
||||
ID.AddPointer(Tag);
|
||||
ID.AddPointer(getTag());
|
||||
}
|
||||
|
||||
static ProgramPoint getProgramPoint(const Stmt *S, ProgramPoint::Kind K,
|
||||
|
|
@ -304,7 +318,7 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
/// \class Represents a program point after a store evaluation.
|
||||
/// \brief Represents a program point after a store evaluation.
|
||||
class PostStore : public PostStmt {
|
||||
public:
|
||||
/// Construct the post store point.
|
||||
|
|
@ -340,14 +354,29 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
class PostPurgeDeadSymbols : public PostStmt {
|
||||
/// Represents a point after we ran remove dead bindings BEFORE
|
||||
/// processing the given statement.
|
||||
class PreStmtPurgeDeadSymbols : public StmtPoint {
|
||||
public:
|
||||
PostPurgeDeadSymbols(const Stmt *S, const LocationContext *L,
|
||||
PreStmtPurgeDeadSymbols(const Stmt *S, const LocationContext *L,
|
||||
const ProgramPointTag *tag = 0)
|
||||
: PostStmt(S, PostPurgeDeadSymbolsKind, L, tag) {}
|
||||
: StmtPoint(S, 0, PreStmtPurgeDeadSymbolsKind, L, tag) { }
|
||||
|
||||
static bool classof(const ProgramPoint* Location) {
|
||||
return Location->getKind() == PostPurgeDeadSymbolsKind;
|
||||
return Location->getKind() == PreStmtPurgeDeadSymbolsKind;
|
||||
}
|
||||
};
|
||||
|
||||
/// Represents a point after we ran remove dead bindings AFTER
|
||||
/// processing the given statement.
|
||||
class PostStmtPurgeDeadSymbols : public StmtPoint {
|
||||
public:
|
||||
PostStmtPurgeDeadSymbols(const Stmt *S, const LocationContext *L,
|
||||
const ProgramPointTag *tag = 0)
|
||||
: StmtPoint(S, 0, PostStmtPurgeDeadSymbolsKind, L, tag) { }
|
||||
|
||||
static bool classof(const ProgramPoint* Location) {
|
||||
return Location->getKind() == PostStmtPurgeDeadSymbolsKind;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -383,11 +412,60 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
class CallEnter : public StmtPoint {
|
||||
/// Represents an implicit call event.
|
||||
///
|
||||
/// The nearest statement is provided for diagnostic purposes.
|
||||
class ImplicitCallPoint : public ProgramPoint {
|
||||
public:
|
||||
ImplicitCallPoint(const Decl *D, SourceLocation Loc, Kind K,
|
||||
const LocationContext *L, const ProgramPointTag *Tag)
|
||||
: ProgramPoint(Loc.getPtrEncoding(), D, K, L, Tag) {}
|
||||
|
||||
const Decl *getDecl() const { return static_cast<const Decl *>(getData2()); }
|
||||
SourceLocation getLocation() const {
|
||||
return SourceLocation::getFromPtrEncoding(getData1());
|
||||
}
|
||||
|
||||
static bool classof(const ProgramPoint *Location) {
|
||||
return Location->getKind() >= MinImplicitCallKind &&
|
||||
Location->getKind() <= MaxImplicitCallKind;
|
||||
}
|
||||
};
|
||||
|
||||
/// Represents a program point just before an implicit call event.
|
||||
///
|
||||
/// Explicit calls will appear as PreStmt program points.
|
||||
class PreImplicitCall : public ImplicitCallPoint {
|
||||
public:
|
||||
PreImplicitCall(const Decl *D, SourceLocation Loc,
|
||||
const LocationContext *L, const ProgramPointTag *Tag = 0)
|
||||
: ImplicitCallPoint(D, Loc, PreImplicitCallKind, L, Tag) {}
|
||||
|
||||
static bool classof(const ProgramPoint *Location) {
|
||||
return Location->getKind() == PreImplicitCallKind;
|
||||
}
|
||||
};
|
||||
|
||||
/// Represents a program point just after an implicit call event.
|
||||
///
|
||||
/// Explicit calls will appear as PostStmt program points.
|
||||
class PostImplicitCall : public ImplicitCallPoint {
|
||||
public:
|
||||
PostImplicitCall(const Decl *D, SourceLocation Loc,
|
||||
const LocationContext *L, const ProgramPointTag *Tag = 0)
|
||||
: ImplicitCallPoint(D, Loc, PostImplicitCallKind, L, Tag) {}
|
||||
|
||||
static bool classof(const ProgramPoint *Location) {
|
||||
return Location->getKind() == PostImplicitCallKind;
|
||||
}
|
||||
};
|
||||
|
||||
/// Represents a point when we begin processing an inlined call.
|
||||
class CallEnter : public ProgramPoint {
|
||||
public:
|
||||
CallEnter(const Stmt *stmt, const StackFrameContext *calleeCtx,
|
||||
const LocationContext *callerCtx)
|
||||
: StmtPoint(stmt, calleeCtx, CallEnterKind, callerCtx, 0) {}
|
||||
: ProgramPoint(stmt, calleeCtx, CallEnterKind, callerCtx, 0) {}
|
||||
|
||||
const Stmt *getCallExpr() const {
|
||||
return static_cast<const Stmt *>(getData1());
|
||||
|
|
@ -402,14 +480,41 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
class CallExit : public StmtPoint {
|
||||
/// Represents a point when we start the call exit sequence (for inlined call).
|
||||
///
|
||||
/// The call exit is simulated with a sequence of nodes, which occur between
|
||||
/// CallExitBegin and CallExitEnd. The following operations occur between the
|
||||
/// two program points:
|
||||
/// - CallExitBegin
|
||||
/// - Bind the return value
|
||||
/// - Run Remove dead bindings (to clean up the dead symbols from the callee).
|
||||
/// - CallExitEnd
|
||||
class CallExitBegin : public ProgramPoint {
|
||||
public:
|
||||
// CallExit uses the callee's location context.
|
||||
CallExit(const Stmt *S, const LocationContext *L)
|
||||
: StmtPoint(S, 0, CallExitKind, L, 0) {}
|
||||
// CallExitBegin uses the callee's location context.
|
||||
CallExitBegin(const StackFrameContext *L)
|
||||
: ProgramPoint(0, CallExitBeginKind, L, 0) {}
|
||||
|
||||
static bool classof(const ProgramPoint *Location) {
|
||||
return Location->getKind() == CallExitKind;
|
||||
return Location->getKind() == CallExitBeginKind;
|
||||
}
|
||||
};
|
||||
|
||||
/// Represents a point when we finish the call exit sequence (for inlined call).
|
||||
/// \sa CallExitBegin
|
||||
class CallExitEnd : public ProgramPoint {
|
||||
public:
|
||||
// CallExitEnd uses the caller's location context.
|
||||
CallExitEnd(const StackFrameContext *CalleeCtx,
|
||||
const LocationContext *CallerCtx)
|
||||
: ProgramPoint(CalleeCtx, CallExitEndKind, CallerCtx, 0) {}
|
||||
|
||||
const StackFrameContext *getCalleeContext() const {
|
||||
return static_cast<const StackFrameContext *>(getData1());
|
||||
}
|
||||
|
||||
static bool classof(const ProgramPoint *Location) {
|
||||
return Location->getKind() == CallExitEndKind;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ public:
|
|||
DISPATCH_CASE(Field)
|
||||
DISPATCH_CASE(UsingDirective)
|
||||
DISPATCH_CASE(Using)
|
||||
DISPATCH_CASE(NamespaceAlias)
|
||||
default:
|
||||
llvm_unreachable("Subtype of ScopedDecl not handled.");
|
||||
}
|
||||
|
|
@ -90,6 +91,7 @@ public:
|
|||
DEFAULT_DISPATCH(ObjCCategory)
|
||||
DEFAULT_DISPATCH(UsingDirective)
|
||||
DEFAULT_DISPATCH(Using)
|
||||
DEFAULT_DISPATCH(NamespaceAlias)
|
||||
|
||||
void VisitCXXRecordDecl(CXXRecordDecl *D) {
|
||||
static_cast<ImplClass*>(this)->VisitRecordDecl(D);
|
||||
|
|
|
|||
|
|
@ -6,10 +6,11 @@
|
|||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// These enums/classes describe ABI related information about constructors,
|
||||
// destructors and thunks.
|
||||
//
|
||||
///
|
||||
/// \file
|
||||
/// \brief Enums/classes describing ABI related information about constructors,
|
||||
/// destructors and thunks.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef CLANG_BASIC_ABI_H
|
||||
|
|
@ -19,27 +20,27 @@
|
|||
|
||||
namespace clang {
|
||||
|
||||
/// CXXCtorType - C++ constructor types
|
||||
/// \brief C++ constructor types.
|
||||
enum CXXCtorType {
|
||||
Ctor_Complete, // Complete object ctor
|
||||
Ctor_Base, // Base object ctor
|
||||
Ctor_CompleteAllocating // Complete object allocating ctor
|
||||
Ctor_Complete, ///< Complete object ctor
|
||||
Ctor_Base, ///< Base object ctor
|
||||
Ctor_CompleteAllocating ///< Complete object allocating ctor
|
||||
};
|
||||
|
||||
/// CXXDtorType - C++ destructor types
|
||||
/// \brief C++ destructor types.
|
||||
enum CXXDtorType {
|
||||
Dtor_Deleting, // Deleting dtor
|
||||
Dtor_Complete, // Complete object dtor
|
||||
Dtor_Base // Base object dtor
|
||||
Dtor_Deleting, ///< Deleting dtor
|
||||
Dtor_Complete, ///< Complete object dtor
|
||||
Dtor_Base ///< Base object dtor
|
||||
};
|
||||
|
||||
/// ReturnAdjustment - A return adjustment.
|
||||
/// \brief A return adjustment.
|
||||
struct ReturnAdjustment {
|
||||
/// NonVirtual - The non-virtual adjustment from the derived object to its
|
||||
/// \brief The non-virtual adjustment from the derived object to its
|
||||
/// nearest virtual base.
|
||||
int64_t NonVirtual;
|
||||
|
||||
/// VBaseOffsetOffset - The offset (in bytes), relative to the address point
|
||||
/// \brief The offset (in bytes), relative to the address point
|
||||
/// of the virtual base class offset.
|
||||
int64_t VBaseOffsetOffset;
|
||||
|
||||
|
|
@ -63,13 +64,13 @@ struct ReturnAdjustment {
|
|||
}
|
||||
};
|
||||
|
||||
/// ThisAdjustment - A 'this' pointer adjustment.
|
||||
/// \brief A \c this pointer adjustment.
|
||||
struct ThisAdjustment {
|
||||
/// NonVirtual - The non-virtual adjustment from the derived object to its
|
||||
/// \brief The non-virtual adjustment from the derived object to its
|
||||
/// nearest virtual base.
|
||||
int64_t NonVirtual;
|
||||
|
||||
/// VCallOffsetOffset - The offset (in bytes), relative to the address point,
|
||||
/// \brief The offset (in bytes), relative to the address point,
|
||||
/// of the virtual call offset.
|
||||
int64_t VCallOffsetOffset;
|
||||
|
||||
|
|
@ -93,13 +94,13 @@ struct ThisAdjustment {
|
|||
}
|
||||
};
|
||||
|
||||
/// ThunkInfo - The 'this' pointer adjustment as well as an optional return
|
||||
/// \brief The \c this pointer adjustment as well as an optional return
|
||||
/// adjustment for a thunk.
|
||||
struct ThunkInfo {
|
||||
/// This - The 'this' pointer adjustment.
|
||||
/// \brief The \c this pointer adjustment.
|
||||
ThisAdjustment This;
|
||||
|
||||
/// Return - The return adjustment.
|
||||
/// \brief The return adjustment.
|
||||
ReturnAdjustment Return;
|
||||
|
||||
ThunkInfo() { }
|
||||
|
|
|
|||
|
|
@ -6,10 +6,11 @@
|
|||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file provides definitions for the various language-specific address
|
||||
// spaces.
|
||||
//
|
||||
///
|
||||
/// \file
|
||||
/// \brief Provides definitions for the various language-specific address
|
||||
/// spaces.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_BASIC_ADDRESSSPACES_H
|
||||
|
|
@ -19,8 +20,9 @@ namespace clang {
|
|||
|
||||
namespace LangAS {
|
||||
|
||||
/// This enum defines the set of possible language-specific address spaces.
|
||||
/// It uses a high starting offset so as not to conflict with any address
|
||||
/// \brief Defines the set of possible language-specific address spaces.
|
||||
///
|
||||
/// This uses a high starting offset so as not to conflict with any address
|
||||
/// space used by a target.
|
||||
enum ID {
|
||||
Offset = 0xFFFF00,
|
||||
|
|
@ -29,6 +31,10 @@ enum ID {
|
|||
opencl_local,
|
||||
opencl_constant,
|
||||
|
||||
cuda_device,
|
||||
cuda_constant,
|
||||
cuda_shared,
|
||||
|
||||
Last,
|
||||
Count = Last-Offset
|
||||
};
|
||||
|
|
|
|||
|
|
@ -6,16 +6,17 @@
|
|||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file includes all the separate Diagnostic headers & some related
|
||||
// helpers.
|
||||
//
|
||||
///
|
||||
/// \file
|
||||
/// \brief Includes all the separate Diagnostic headers & some related helpers.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ALL_DIAGNOSTICS_H
|
||||
#define LLVM_CLANG_ALL_DIAGNOSTICS_H
|
||||
|
||||
#include "clang/AST/ASTDiagnostic.h"
|
||||
#include "clang/AST/CommentDiagnostic.h"
|
||||
#include "clang/Analysis/AnalysisDiagnostic.h"
|
||||
#include "clang/Driver/DriverDiagnostic.h"
|
||||
#include "clang/Frontend/FrontendDiagnostic.h"
|
||||
|
|
|
|||
|
|
@ -80,23 +80,40 @@ class EnumArgument<string name, string type, list<string> values,
|
|||
list<string> Enums = enums;
|
||||
}
|
||||
|
||||
// This handles one spelling of an attribute.
|
||||
class Spelling<string name, string variety> {
|
||||
string Name = name;
|
||||
string Variety = variety;
|
||||
}
|
||||
|
||||
class GNU<string name> : Spelling<name, "GNU">;
|
||||
class Declspec<string name> : Spelling<name, "Declspec">;
|
||||
class CXX11<string namespace, string name> : Spelling<name, "CXX11"> {
|
||||
string Namespace = namespace;
|
||||
}
|
||||
|
||||
class Attr {
|
||||
// The various ways in which an attribute can be spelled in source
|
||||
list<string> Spellings;
|
||||
list<Spelling> Spellings;
|
||||
// The things to which an attribute can appertain
|
||||
list<AttrSubject> Subjects;
|
||||
// The arguments allowed on an attribute
|
||||
list<Argument> Args = [];
|
||||
// The namespaces in which the attribute appears in C++0x attributes.
|
||||
// The attribute will not be permitted in C++0x attribute-specifiers if
|
||||
// this is empty; the empty string can be used as a namespace.
|
||||
list<string> Namespaces = [];
|
||||
// Set to true for attributes with arguments which require delayed parsing.
|
||||
bit LateParsed = 0;
|
||||
// Set to false to prevent an attribute from being propagated from a template
|
||||
// to the instantiation.
|
||||
bit Clone = 1;
|
||||
// Set to true for attributes which must be instantiated within templates
|
||||
bit TemplateDependent = 0;
|
||||
// Set to true for attributes that have a corresponding AST node.
|
||||
bit ASTNode = 1;
|
||||
// Set to true for attributes which have handler in Sema.
|
||||
bit SemaHandler = 1;
|
||||
// Set to true for attributes that are completely ignored.
|
||||
bit Ignored = 0;
|
||||
// Set to true if each of the spellings is a distinct attribute.
|
||||
bit DistinctSpellings = 0;
|
||||
// Any additional text that should be included verbatim in the class.
|
||||
code AdditionalMembers = [{}];
|
||||
}
|
||||
|
|
@ -112,16 +129,21 @@ class InheritableParamAttr : InheritableAttr;
|
|||
// Attributes begin here
|
||||
//
|
||||
|
||||
def AddressSpace : Attr {
|
||||
let Spellings = [GNU<"address_space">];
|
||||
let Args = [IntArgument<"AddressSpace">];
|
||||
let ASTNode = 0;
|
||||
}
|
||||
|
||||
def Alias : InheritableAttr {
|
||||
let Spellings = ["alias"];
|
||||
let Spellings = [GNU<"alias">];
|
||||
let Args = [StringArgument<"Aliasee">];
|
||||
}
|
||||
|
||||
def Aligned : InheritableAttr {
|
||||
let Spellings = ["aligned"];
|
||||
let Spellings = [GNU<"aligned">, GNU<"align">];
|
||||
let Subjects = [NonBitField, NormalVar, Tag];
|
||||
let Args = [AlignedArgument<"Alignment">];
|
||||
let Namespaces = ["", "std"];
|
||||
let Args = [AlignedArgument<"Alignment">, BoolArgument<"IsMSDeclSpec">];
|
||||
}
|
||||
|
||||
def AlignMac68k : InheritableAttr {
|
||||
|
|
@ -129,16 +151,27 @@ def AlignMac68k : InheritableAttr {
|
|||
let SemaHandler = 0;
|
||||
}
|
||||
|
||||
def AllocSize : Attr {
|
||||
let Spellings = [GNU<"alloc_size">];
|
||||
let Args = [VariadicUnsignedArgument<"Args">];
|
||||
}
|
||||
|
||||
def AlwaysInline : InheritableAttr {
|
||||
let Spellings = ["always_inline"];
|
||||
let Spellings = [GNU<"always_inline">];
|
||||
}
|
||||
|
||||
def TLSModel : InheritableAttr {
|
||||
let Spellings = [GNU<"tls_model">];
|
||||
let Subjects = [Var];
|
||||
let Args = [StringArgument<"Model">];
|
||||
}
|
||||
|
||||
def AnalyzerNoReturn : InheritableAttr {
|
||||
let Spellings = ["analyzer_noreturn"];
|
||||
let Spellings = [GNU<"analyzer_noreturn">];
|
||||
}
|
||||
|
||||
def Annotate : InheritableParamAttr {
|
||||
let Spellings = ["annotate"];
|
||||
let Spellings = [GNU<"annotate">];
|
||||
let Args = [StringArgument<"Annotation">];
|
||||
}
|
||||
|
||||
|
|
@ -149,7 +182,7 @@ def AsmLabel : InheritableAttr {
|
|||
}
|
||||
|
||||
def Availability : InheritableAttr {
|
||||
let Spellings = ["availability"];
|
||||
let Spellings = [GNU<"availability">];
|
||||
let Args = [IdentifierArgument<"platform">, VersionArgument<"introduced">,
|
||||
VersionArgument<"deprecated">, VersionArgument<"obsoleted">,
|
||||
BoolArgument<"unavailable">, StringArgument<"message">];
|
||||
|
|
@ -163,18 +196,25 @@ def Availability : InheritableAttr {
|
|||
}
|
||||
|
||||
def Blocks : InheritableAttr {
|
||||
let Spellings = ["blocks"];
|
||||
let Spellings = [GNU<"blocks">];
|
||||
let Args = [EnumArgument<"Type", "BlockType", ["byref"], ["ByRef"]>];
|
||||
}
|
||||
|
||||
def Bounded : Attr {
|
||||
let Spellings = [GNU<"bounded">];
|
||||
let ASTNode = 0;
|
||||
let SemaHandler = 0;
|
||||
let Ignored = 1;
|
||||
}
|
||||
|
||||
def CarriesDependency : InheritableParamAttr {
|
||||
let Spellings = ["carries_dependency"];
|
||||
let Spellings = [GNU<"carries_dependency">, CXX11<"","carries_dependency">,
|
||||
CXX11<"std","carries_dependency">];
|
||||
let Subjects = [ParmVar, Function];
|
||||
let Namespaces = ["", "std"];
|
||||
}
|
||||
|
||||
def CDecl : InheritableAttr {
|
||||
let Spellings = ["cdecl", "__cdecl"];
|
||||
let Spellings = [GNU<"cdecl">, GNU<"__cdecl">];
|
||||
}
|
||||
|
||||
// cf_audited_transfer indicates that the given function has been
|
||||
|
|
@ -182,7 +222,7 @@ def CDecl : InheritableAttr {
|
|||
// cf_returns_retained attributes. It is generally applied by
|
||||
// '#pragma clang arc_cf_code_audited' rather than explicitly.
|
||||
def CFAuditedTransfer : InheritableAttr {
|
||||
let Spellings = ["cf_audited_transfer"];
|
||||
let Spellings = [GNU<"cf_audited_transfer">];
|
||||
let Subjects = [Function];
|
||||
}
|
||||
|
||||
|
|
@ -190,133 +230,151 @@ def CFAuditedTransfer : InheritableAttr {
|
|||
// It indicates that the function has unknown or unautomatable
|
||||
// transfer semantics.
|
||||
def CFUnknownTransfer : InheritableAttr {
|
||||
let Spellings = ["cf_unknown_transfer"];
|
||||
let Spellings = [GNU<"cf_unknown_transfer">];
|
||||
let Subjects = [Function];
|
||||
}
|
||||
|
||||
def CFReturnsAutoreleased : Attr {
|
||||
let Spellings = [GNU<"cf_returns_autoreleased">];
|
||||
let ASTNode = 0;
|
||||
}
|
||||
|
||||
def CFReturnsRetained : InheritableAttr {
|
||||
let Spellings = ["cf_returns_retained"];
|
||||
let Spellings = [GNU<"cf_returns_retained">];
|
||||
let Subjects = [ObjCMethod, Function];
|
||||
}
|
||||
|
||||
def CFReturnsNotRetained : InheritableAttr {
|
||||
let Spellings = ["cf_returns_not_retained"];
|
||||
let Spellings = [GNU<"cf_returns_not_retained">];
|
||||
let Subjects = [ObjCMethod, Function];
|
||||
}
|
||||
|
||||
def CFConsumed : InheritableParamAttr {
|
||||
let Spellings = ["cf_consumed"];
|
||||
let Spellings = [GNU<"cf_consumed">];
|
||||
let Subjects = [ParmVar];
|
||||
}
|
||||
|
||||
def Cleanup : InheritableAttr {
|
||||
let Spellings = ["cleanup"];
|
||||
let Spellings = [GNU<"cleanup">];
|
||||
let Args = [FunctionArgument<"FunctionDecl">];
|
||||
}
|
||||
|
||||
def Cold : InheritableAttr {
|
||||
let Spellings = [GNU<"cold">];
|
||||
}
|
||||
|
||||
def Common : InheritableAttr {
|
||||
let Spellings = ["common"];
|
||||
let Spellings = [GNU<"common">];
|
||||
}
|
||||
|
||||
def Const : InheritableAttr {
|
||||
let Spellings = ["const"];
|
||||
let Spellings = [GNU<"const">, GNU<"__const">];
|
||||
}
|
||||
|
||||
def Constructor : InheritableAttr {
|
||||
let Spellings = ["constructor"];
|
||||
let Spellings = [GNU<"constructor">];
|
||||
let Args = [IntArgument<"Priority">];
|
||||
}
|
||||
|
||||
def CUDAConstant : InheritableAttr {
|
||||
let Spellings = ["constant"];
|
||||
let Spellings = [GNU<"constant">];
|
||||
}
|
||||
|
||||
def CUDADevice : Attr {
|
||||
let Spellings = ["device"];
|
||||
def CUDADevice : InheritableAttr {
|
||||
let Spellings = [GNU<"device">];
|
||||
}
|
||||
|
||||
def CUDAGlobal : InheritableAttr {
|
||||
let Spellings = ["global"];
|
||||
let Spellings = [GNU<"global">];
|
||||
}
|
||||
|
||||
def CUDAHost : Attr {
|
||||
let Spellings = ["host"];
|
||||
def CUDAHost : InheritableAttr {
|
||||
let Spellings = [GNU<"host">];
|
||||
}
|
||||
|
||||
def CUDALaunchBounds : InheritableAttr {
|
||||
let Spellings = ["launch_bounds"];
|
||||
let Spellings = [GNU<"launch_bounds">];
|
||||
let Args = [IntArgument<"MaxThreads">, DefaultIntArgument<"MinBlocks", 0>];
|
||||
}
|
||||
|
||||
def CUDAShared : InheritableAttr {
|
||||
let Spellings = ["shared"];
|
||||
let Spellings = [GNU<"shared">];
|
||||
}
|
||||
|
||||
def OpenCLKernel : Attr {
|
||||
let Spellings = ["opencl_kernel_function"];
|
||||
let Spellings = [GNU<"opencl_kernel_function">];
|
||||
}
|
||||
|
||||
def OpenCLImageAccess : Attr {
|
||||
let Spellings = [GNU<"opencl_image_access">];
|
||||
let Args = [IntArgument<"Access">];
|
||||
let ASTNode = 0;
|
||||
}
|
||||
|
||||
def Deprecated : InheritableAttr {
|
||||
let Spellings = ["deprecated"];
|
||||
let Spellings = [GNU<"deprecated">];
|
||||
let Args = [StringArgument<"Message">];
|
||||
}
|
||||
|
||||
def Destructor : InheritableAttr {
|
||||
let Spellings = ["destructor"];
|
||||
let Spellings = [GNU<"destructor">];
|
||||
let Args = [IntArgument<"Priority">];
|
||||
}
|
||||
|
||||
def DLLExport : InheritableAttr {
|
||||
let Spellings = ["dllexport"];
|
||||
def ExtVectorType : Attr {
|
||||
let Spellings = [GNU<"ext_vector_type">];
|
||||
let Args = [ExprArgument<"NumElements">];
|
||||
let ASTNode = 0;
|
||||
}
|
||||
|
||||
def DLLImport : InheritableAttr {
|
||||
let Spellings = ["dllimport"];
|
||||
def FallThrough : Attr {
|
||||
let Spellings = [CXX11<"clang","fallthrough">];
|
||||
let Subjects = [NullStmt];
|
||||
}
|
||||
|
||||
def FastCall : InheritableAttr {
|
||||
let Spellings = ["fastcall", "__fastcall"];
|
||||
let Spellings = [GNU<"fastcall">, GNU<"__fastcall">];
|
||||
}
|
||||
|
||||
def Final : InheritableAttr {
|
||||
def Final : InheritableAttr {
|
||||
let Spellings = [];
|
||||
let SemaHandler = 0;
|
||||
}
|
||||
|
||||
def MsStruct : InheritableAttr {
|
||||
let Spellings = ["__ms_struct__"];
|
||||
}
|
||||
|
||||
def Format : InheritableAttr {
|
||||
let Spellings = ["format"];
|
||||
let Spellings = [GNU<"format">];
|
||||
let Args = [StringArgument<"Type">, IntArgument<"FormatIdx">,
|
||||
IntArgument<"FirstArg">];
|
||||
}
|
||||
|
||||
def FormatArg : InheritableAttr {
|
||||
let Spellings = ["format_arg"];
|
||||
let Spellings = [GNU<"format_arg">];
|
||||
let Args = [IntArgument<"FormatIdx">];
|
||||
}
|
||||
|
||||
def GNUInline : InheritableAttr {
|
||||
let Spellings = ["gnu_inline"];
|
||||
let Spellings = [GNU<"gnu_inline">];
|
||||
}
|
||||
|
||||
def Hot : InheritableAttr {
|
||||
let Spellings = [GNU<"hot">];
|
||||
}
|
||||
|
||||
def IBAction : InheritableAttr {
|
||||
let Spellings = ["ibaction"];
|
||||
let Spellings = [GNU<"ibaction">];
|
||||
}
|
||||
|
||||
def IBOutlet : InheritableAttr {
|
||||
let Spellings = ["iboutlet"];
|
||||
let Spellings = [GNU<"iboutlet">];
|
||||
}
|
||||
|
||||
def IBOutletCollection : InheritableAttr {
|
||||
let Spellings = ["iboutletcollection"];
|
||||
let Spellings = [GNU<"iboutletcollection">];
|
||||
let Args = [TypeArgument<"Interface">, SourceLocArgument<"InterfaceLoc">];
|
||||
}
|
||||
|
||||
def Malloc : InheritableAttr {
|
||||
let Spellings = ["malloc"];
|
||||
let Spellings = [GNU<"malloc">];
|
||||
}
|
||||
|
||||
def MaxFieldAlignment : InheritableAttr {
|
||||
|
|
@ -326,7 +384,7 @@ def MaxFieldAlignment : InheritableAttr {
|
|||
}
|
||||
|
||||
def MayAlias : InheritableAttr {
|
||||
let Spellings = ["may_alias"];
|
||||
let Spellings = [GNU<"may_alias">];
|
||||
}
|
||||
|
||||
def MSP430Interrupt : InheritableAttr {
|
||||
|
|
@ -345,28 +403,46 @@ def MBlazeSaveVolatiles : InheritableAttr {
|
|||
let SemaHandler = 0;
|
||||
}
|
||||
|
||||
def Mode : Attr {
|
||||
let Spellings = [GNU<"mode">];
|
||||
let Args = [IdentifierArgument<"Mode">];
|
||||
let ASTNode = 0;
|
||||
}
|
||||
|
||||
def Naked : InheritableAttr {
|
||||
let Spellings = ["naked"];
|
||||
let Spellings = [GNU<"naked">];
|
||||
}
|
||||
|
||||
def NeonPolyVectorType : Attr {
|
||||
let Spellings = [GNU<"neon_polyvector_type">];
|
||||
let Args = [IntArgument<"NumElements">];
|
||||
let ASTNode = 0;
|
||||
}
|
||||
|
||||
def NeonVectorType : Attr {
|
||||
let Spellings = [GNU<"neon_vector_type">];
|
||||
let Args = [IntArgument<"NumElements">];
|
||||
let ASTNode = 0;
|
||||
}
|
||||
|
||||
def ReturnsTwice : InheritableAttr {
|
||||
let Spellings = ["returns_twice"];
|
||||
let Spellings = [GNU<"returns_twice">];
|
||||
}
|
||||
|
||||
def NoCommon : InheritableAttr {
|
||||
let Spellings = ["nocommon"];
|
||||
let Spellings = [GNU<"nocommon">];
|
||||
}
|
||||
|
||||
def NoDebug : InheritableAttr {
|
||||
let Spellings = ["nodebug"];
|
||||
let Spellings = [GNU<"nodebug">];
|
||||
}
|
||||
|
||||
def NoInline : InheritableAttr {
|
||||
let Spellings = ["noinline"];
|
||||
let Spellings = [GNU<"noinline">];
|
||||
}
|
||||
|
||||
def NonNull : InheritableAttr {
|
||||
let Spellings = ["nonnull"];
|
||||
let Spellings = [GNU<"nonnull">];
|
||||
let Args = [VariadicUnsignedArgument<"Args">];
|
||||
let AdditionalMembers =
|
||||
[{bool isNonNull(unsigned idx) const {
|
||||
|
|
@ -379,58 +455,58 @@ def NonNull : InheritableAttr {
|
|||
}
|
||||
|
||||
def NoReturn : InheritableAttr {
|
||||
let Spellings = ["noreturn"];
|
||||
let Spellings = [GNU<"noreturn">, CXX11<"","noreturn">,
|
||||
CXX11<"std","noreturn">];
|
||||
// FIXME: Does GCC allow this on the function instead?
|
||||
let Subjects = [Function];
|
||||
let Namespaces = ["", "std"];
|
||||
}
|
||||
|
||||
def NoInstrumentFunction : InheritableAttr {
|
||||
let Spellings = ["no_instrument_function"];
|
||||
let Spellings = [GNU<"no_instrument_function">];
|
||||
let Subjects = [Function];
|
||||
}
|
||||
|
||||
def NoThrow : InheritableAttr {
|
||||
let Spellings = ["nothrow"];
|
||||
let Spellings = [GNU<"nothrow">];
|
||||
}
|
||||
|
||||
def NSBridged : InheritableAttr {
|
||||
let Spellings = ["ns_bridged"];
|
||||
let Spellings = [GNU<"ns_bridged">];
|
||||
let Subjects = [Record];
|
||||
let Args = [IdentifierArgument<"BridgedType">];
|
||||
}
|
||||
|
||||
def NSReturnsRetained : InheritableAttr {
|
||||
let Spellings = ["ns_returns_retained"];
|
||||
let Spellings = [GNU<"ns_returns_retained">];
|
||||
let Subjects = [ObjCMethod, Function];
|
||||
}
|
||||
|
||||
def NSReturnsNotRetained : InheritableAttr {
|
||||
let Spellings = ["ns_returns_not_retained"];
|
||||
let Spellings = [GNU<"ns_returns_not_retained">];
|
||||
let Subjects = [ObjCMethod, Function];
|
||||
}
|
||||
|
||||
def NSReturnsAutoreleased : InheritableAttr {
|
||||
let Spellings = ["ns_returns_autoreleased"];
|
||||
let Spellings = [GNU<"ns_returns_autoreleased">];
|
||||
let Subjects = [ObjCMethod, Function];
|
||||
}
|
||||
|
||||
def NSConsumesSelf : InheritableAttr {
|
||||
let Spellings = ["ns_consumes_self"];
|
||||
let Spellings = [GNU<"ns_consumes_self">];
|
||||
let Subjects = [ObjCMethod];
|
||||
}
|
||||
|
||||
def NSConsumed : InheritableParamAttr {
|
||||
let Spellings = ["ns_consumed"];
|
||||
let Spellings = [GNU<"ns_consumed">];
|
||||
let Subjects = [ParmVar];
|
||||
}
|
||||
|
||||
def ObjCException : InheritableAttr {
|
||||
let Spellings = ["objc_exception"];
|
||||
let Spellings = [GNU<"objc_exception">];
|
||||
}
|
||||
|
||||
def ObjCMethodFamily : InheritableAttr {
|
||||
let Spellings = ["objc_method_family"];
|
||||
let Spellings = [GNU<"objc_method_family">];
|
||||
let Subjects = [ObjCMethod];
|
||||
let Args = [EnumArgument<"Family", "FamilyKind",
|
||||
["none", "alloc", "copy", "init", "mutableCopy", "new"],
|
||||
|
|
@ -439,26 +515,26 @@ def ObjCMethodFamily : InheritableAttr {
|
|||
}
|
||||
|
||||
def ObjCNSObject : InheritableAttr {
|
||||
let Spellings = ["NSObject"];
|
||||
let Spellings = [GNU<"NSObject">];
|
||||
}
|
||||
|
||||
def ObjCPreciseLifetime : Attr {
|
||||
let Spellings = ["objc_precise_lifetime"];
|
||||
let Spellings = [GNU<"objc_precise_lifetime">];
|
||||
let Subjects = [Var];
|
||||
}
|
||||
|
||||
def ObjCReturnsInnerPointer : Attr {
|
||||
let Spellings = ["objc_returns_inner_pointer"];
|
||||
let Spellings = [GNU<"objc_returns_inner_pointer">];
|
||||
let Subjects = [ObjCMethod];
|
||||
}
|
||||
|
||||
def ObjCRootClass : Attr {
|
||||
let Spellings = ["objc_root_class"];
|
||||
let Spellings = [GNU<"objc_root_class">];
|
||||
let Subjects = [ObjCInterface];
|
||||
}
|
||||
|
||||
def Overloadable : Attr {
|
||||
let Spellings = ["overloadable"];
|
||||
let Spellings = [GNU<"overloadable">];
|
||||
}
|
||||
|
||||
def Override : InheritableAttr {
|
||||
|
|
@ -467,7 +543,9 @@ def Override : InheritableAttr {
|
|||
}
|
||||
|
||||
def Ownership : InheritableAttr {
|
||||
let Spellings = ["ownership_holds", "ownership_returns", "ownership_takes"];
|
||||
let Spellings = [GNU<"ownership_holds">, GNU<"ownership_returns">,
|
||||
GNU<"ownership_takes">];
|
||||
let DistinctSpellings = 1;
|
||||
let Args = [EnumArgument<"OwnKind", "OwnershipKind",
|
||||
["ownership_holds", "ownership_returns", "ownership_takes"],
|
||||
["Holds", "Returns", "Takes"]>,
|
||||
|
|
@ -475,118 +553,151 @@ def Ownership : InheritableAttr {
|
|||
}
|
||||
|
||||
def Packed : InheritableAttr {
|
||||
let Spellings = ["packed"];
|
||||
let Spellings = [GNU<"packed">];
|
||||
}
|
||||
|
||||
def Pcs : InheritableAttr {
|
||||
let Spellings = ["pcs"];
|
||||
let Spellings = [GNU<"pcs">];
|
||||
let Args = [EnumArgument<"PCS", "PCSType",
|
||||
["aapcs", "aapcs-vfp"],
|
||||
["AAPCS", "AAPCS_VFP"]>];
|
||||
}
|
||||
|
||||
def Pure : InheritableAttr {
|
||||
let Spellings = ["pure"];
|
||||
let Spellings = [GNU<"pure">];
|
||||
}
|
||||
|
||||
def Regparm : InheritableAttr {
|
||||
let Spellings = ["regparm"];
|
||||
let Spellings = [GNU<"regparm">];
|
||||
let Args = [UnsignedArgument<"NumParams">];
|
||||
}
|
||||
|
||||
def ReqdWorkGroupSize : InheritableAttr {
|
||||
let Spellings = ["reqd_work_group_size"];
|
||||
let Spellings = [GNU<"reqd_work_group_size">];
|
||||
let Args = [UnsignedArgument<"XDim">, UnsignedArgument<"YDim">,
|
||||
UnsignedArgument<"ZDim">];
|
||||
}
|
||||
|
||||
def WorkGroupSizeHint : InheritableAttr {
|
||||
let Spellings = [GNU<"work_group_size_hint">];
|
||||
let Args = [UnsignedArgument<"XDim">,
|
||||
UnsignedArgument<"YDim">,
|
||||
UnsignedArgument<"ZDim">];
|
||||
}
|
||||
|
||||
def InitPriority : InheritableAttr {
|
||||
let Spellings = ["init_priority"];
|
||||
let Spellings = [GNU<"init_priority">];
|
||||
let Args = [UnsignedArgument<"Priority">];
|
||||
}
|
||||
|
||||
def Section : InheritableAttr {
|
||||
let Spellings = ["section"];
|
||||
let Spellings = [GNU<"section">];
|
||||
let Args = [StringArgument<"Name">];
|
||||
}
|
||||
|
||||
def Sentinel : InheritableAttr {
|
||||
let Spellings = ["sentinel"];
|
||||
let Spellings = [GNU<"sentinel">];
|
||||
let Args = [DefaultIntArgument<"Sentinel", 0>,
|
||||
DefaultIntArgument<"NullPos", 0>];
|
||||
}
|
||||
|
||||
def StdCall : InheritableAttr {
|
||||
let Spellings = ["stdcall", "__stdcall"];
|
||||
let Spellings = [GNU<"stdcall">, GNU<"__stdcall">];
|
||||
}
|
||||
|
||||
def ThisCall : InheritableAttr {
|
||||
let Spellings = ["thiscall", "__thiscall"];
|
||||
let Spellings = [GNU<"thiscall">, GNU<"__thiscall">];
|
||||
}
|
||||
|
||||
def Pascal : InheritableAttr {
|
||||
let Spellings = ["pascal", "__pascal"];
|
||||
let Spellings = [GNU<"pascal">];
|
||||
}
|
||||
|
||||
def TransparentUnion : InheritableAttr {
|
||||
let Spellings = ["transparent_union"];
|
||||
let Spellings = [GNU<"transparent_union">];
|
||||
}
|
||||
|
||||
def Unavailable : InheritableAttr {
|
||||
let Spellings = ["unavailable"];
|
||||
let Spellings = [GNU<"unavailable">];
|
||||
let Args = [StringArgument<"Message">];
|
||||
}
|
||||
|
||||
def ArcWeakrefUnavailable : InheritableAttr {
|
||||
let Spellings = ["objc_arc_weak_reference_unavailable"];
|
||||
let Spellings = [GNU<"objc_arc_weak_reference_unavailable">];
|
||||
let Subjects = [ObjCInterface];
|
||||
}
|
||||
|
||||
def ObjCGC : Attr {
|
||||
let Spellings = [GNU<"objc_gc">];
|
||||
let Args = [IdentifierArgument<"Kind">];
|
||||
let ASTNode = 0;
|
||||
}
|
||||
|
||||
def ObjCOwnership : Attr {
|
||||
let Spellings = [GNU<"objc_ownership">];
|
||||
let Args = [IdentifierArgument<"Kind">];
|
||||
let ASTNode = 0;
|
||||
}
|
||||
|
||||
def ObjCRequiresPropertyDefs : InheritableAttr {
|
||||
let Spellings = ["objc_requires_property_definitions"];
|
||||
let Spellings = [GNU<"objc_requires_property_definitions">];
|
||||
let Subjects = [ObjCInterface];
|
||||
}
|
||||
|
||||
def Unused : InheritableAttr {
|
||||
let Spellings = ["unused"];
|
||||
let Spellings = [GNU<"unused">];
|
||||
}
|
||||
|
||||
def Used : InheritableAttr {
|
||||
let Spellings = ["used"];
|
||||
let Spellings = [GNU<"used">];
|
||||
}
|
||||
|
||||
def Uuid : InheritableAttr {
|
||||
let Spellings = ["uuid"];
|
||||
let Spellings = [GNU<"uuid">];
|
||||
let Args = [StringArgument<"Guid">];
|
||||
let Subjects = [CXXRecord];
|
||||
}
|
||||
|
||||
def VectorSize : Attr {
|
||||
let Spellings = [GNU<"vector_size">];
|
||||
let Args = [ExprArgument<"NumBytes">];
|
||||
let ASTNode = 0;
|
||||
}
|
||||
|
||||
def VecTypeHint : Attr {
|
||||
let Spellings = [GNU<"vec_type_hint">];
|
||||
let ASTNode = 0;
|
||||
let SemaHandler = 0;
|
||||
let Ignored = 1;
|
||||
}
|
||||
|
||||
def Visibility : InheritableAttr {
|
||||
let Spellings = ["visibility"];
|
||||
let Clone = 0;
|
||||
let Spellings = [GNU<"visibility">];
|
||||
let Args = [EnumArgument<"Visibility", "VisibilityType",
|
||||
["default", "hidden", "internal", "protected"],
|
||||
["Default", "Hidden", "Hidden", "Protected"]>];
|
||||
}
|
||||
|
||||
def VecReturn : InheritableAttr {
|
||||
let Spellings = ["vecreturn"];
|
||||
let Spellings = [GNU<"vecreturn">];
|
||||
let Subjects = [CXXRecord];
|
||||
}
|
||||
|
||||
def WarnUnusedResult : InheritableAttr {
|
||||
let Spellings = ["warn_unused_result"];
|
||||
let Spellings = [GNU<"warn_unused_result">];
|
||||
}
|
||||
|
||||
def Weak : InheritableAttr {
|
||||
let Spellings = ["weak"];
|
||||
let Spellings = [GNU<"weak">];
|
||||
}
|
||||
|
||||
def WeakImport : InheritableAttr {
|
||||
let Spellings = ["weak_import"];
|
||||
let Spellings = [GNU<"weak_import">];
|
||||
}
|
||||
|
||||
def WeakRef : InheritableAttr {
|
||||
let Spellings = ["weakref"];
|
||||
let Spellings = [GNU<"weakref">];
|
||||
}
|
||||
|
||||
def X86ForceAlignArgPointer : InheritableAttr {
|
||||
|
|
@ -595,68 +706,68 @@ def X86ForceAlignArgPointer : InheritableAttr {
|
|||
|
||||
// AddressSafety attribute (e.g. for AddressSanitizer)
|
||||
def NoAddressSafetyAnalysis : InheritableAttr {
|
||||
let Spellings = ["no_address_safety_analysis"];
|
||||
let Spellings = [GNU<"no_address_safety_analysis">];
|
||||
}
|
||||
|
||||
// C/C++ Thread safety attributes (e.g. for deadlock, data race checking)
|
||||
|
||||
def GuardedVar : InheritableAttr {
|
||||
let Spellings = ["guarded_var"];
|
||||
let Spellings = [GNU<"guarded_var">];
|
||||
}
|
||||
|
||||
def PtGuardedVar : InheritableAttr {
|
||||
let Spellings = ["pt_guarded_var"];
|
||||
let Spellings = [GNU<"pt_guarded_var">];
|
||||
}
|
||||
|
||||
def Lockable : InheritableAttr {
|
||||
let Spellings = ["lockable"];
|
||||
let Spellings = [GNU<"lockable">];
|
||||
}
|
||||
|
||||
def ScopedLockable : InheritableAttr {
|
||||
let Spellings = ["scoped_lockable"];
|
||||
let Spellings = [GNU<"scoped_lockable">];
|
||||
}
|
||||
|
||||
def NoThreadSafetyAnalysis : InheritableAttr {
|
||||
let Spellings = ["no_thread_safety_analysis"];
|
||||
let Spellings = [GNU<"no_thread_safety_analysis">];
|
||||
}
|
||||
|
||||
def GuardedBy : InheritableAttr {
|
||||
let Spellings = ["guarded_by"];
|
||||
let Spellings = [GNU<"guarded_by">];
|
||||
let Args = [ExprArgument<"Arg">];
|
||||
let LateParsed = 1;
|
||||
let TemplateDependent = 1;
|
||||
}
|
||||
|
||||
def PtGuardedBy : InheritableAttr {
|
||||
let Spellings = ["pt_guarded_by"];
|
||||
let Spellings = [GNU<"pt_guarded_by">];
|
||||
let Args = [ExprArgument<"Arg">];
|
||||
let LateParsed = 1;
|
||||
let TemplateDependent = 1;
|
||||
}
|
||||
|
||||
def AcquiredAfter : InheritableAttr {
|
||||
let Spellings = ["acquired_after"];
|
||||
let Spellings = [GNU<"acquired_after">];
|
||||
let Args = [VariadicExprArgument<"Args">];
|
||||
let LateParsed = 1;
|
||||
let TemplateDependent = 1;
|
||||
}
|
||||
|
||||
def AcquiredBefore : InheritableAttr {
|
||||
let Spellings = ["acquired_before"];
|
||||
let Spellings = [GNU<"acquired_before">];
|
||||
let Args = [VariadicExprArgument<"Args">];
|
||||
let LateParsed = 1;
|
||||
let TemplateDependent = 1;
|
||||
}
|
||||
|
||||
def ExclusiveLockFunction : InheritableAttr {
|
||||
let Spellings = ["exclusive_lock_function"];
|
||||
let Spellings = [GNU<"exclusive_lock_function">];
|
||||
let Args = [VariadicExprArgument<"Args">];
|
||||
let LateParsed = 1;
|
||||
let TemplateDependent = 1;
|
||||
}
|
||||
|
||||
def SharedLockFunction : InheritableAttr {
|
||||
let Spellings = ["shared_lock_function"];
|
||||
let Spellings = [GNU<"shared_lock_function">];
|
||||
let Args = [VariadicExprArgument<"Args">];
|
||||
let LateParsed = 1;
|
||||
let TemplateDependent = 1;
|
||||
|
|
@ -665,7 +776,7 @@ def SharedLockFunction : InheritableAttr {
|
|||
// The first argument is an integer or boolean value specifying the return value
|
||||
// of a successful lock acquisition.
|
||||
def ExclusiveTrylockFunction : InheritableAttr {
|
||||
let Spellings = ["exclusive_trylock_function"];
|
||||
let Spellings = [GNU<"exclusive_trylock_function">];
|
||||
let Args = [ExprArgument<"SuccessValue">, VariadicExprArgument<"Args">];
|
||||
let LateParsed = 1;
|
||||
let TemplateDependent = 1;
|
||||
|
|
@ -674,43 +785,85 @@ def ExclusiveTrylockFunction : InheritableAttr {
|
|||
// The first argument is an integer or boolean value specifying the return value
|
||||
// of a successful lock acquisition.
|
||||
def SharedTrylockFunction : InheritableAttr {
|
||||
let Spellings = ["shared_trylock_function"];
|
||||
let Spellings = [GNU<"shared_trylock_function">];
|
||||
let Args = [ExprArgument<"SuccessValue">, VariadicExprArgument<"Args">];
|
||||
let LateParsed = 1;
|
||||
let TemplateDependent = 1;
|
||||
}
|
||||
|
||||
def UnlockFunction : InheritableAttr {
|
||||
let Spellings = ["unlock_function"];
|
||||
let Spellings = [GNU<"unlock_function">];
|
||||
let Args = [VariadicExprArgument<"Args">];
|
||||
let LateParsed = 1;
|
||||
let TemplateDependent = 1;
|
||||
}
|
||||
|
||||
def LockReturned : InheritableAttr {
|
||||
let Spellings = ["lock_returned"];
|
||||
let Spellings = [GNU<"lock_returned">];
|
||||
let Args = [ExprArgument<"Arg">];
|
||||
let LateParsed = 1;
|
||||
let TemplateDependent = 1;
|
||||
}
|
||||
|
||||
def LocksExcluded : InheritableAttr {
|
||||
let Spellings = ["locks_excluded"];
|
||||
let Spellings = [GNU<"locks_excluded">];
|
||||
let Args = [VariadicExprArgument<"Args">];
|
||||
let LateParsed = 1;
|
||||
let TemplateDependent = 1;
|
||||
}
|
||||
|
||||
def ExclusiveLocksRequired : InheritableAttr {
|
||||
let Spellings = ["exclusive_locks_required"];
|
||||
let Spellings = [GNU<"exclusive_locks_required">];
|
||||
let Args = [VariadicExprArgument<"Args">];
|
||||
let LateParsed = 1;
|
||||
let TemplateDependent = 1;
|
||||
}
|
||||
|
||||
def SharedLocksRequired : InheritableAttr {
|
||||
let Spellings = ["shared_locks_required"];
|
||||
let Spellings = [GNU<"shared_locks_required">];
|
||||
let Args = [VariadicExprArgument<"Args">];
|
||||
let LateParsed = 1;
|
||||
let TemplateDependent = 1;
|
||||
}
|
||||
|
||||
// Microsoft-related attributes
|
||||
|
||||
def MsStruct : InheritableAttr {
|
||||
let Spellings = [Declspec<"ms_struct">];
|
||||
}
|
||||
|
||||
def DLLExport : InheritableAttr {
|
||||
let Spellings = [Declspec<"dllexport">];
|
||||
}
|
||||
|
||||
def DLLImport : InheritableAttr {
|
||||
let Spellings = [Declspec<"dllimport">];
|
||||
}
|
||||
|
||||
def ForceInline : InheritableAttr {
|
||||
let Spellings = [Declspec<"__forceinline">];
|
||||
}
|
||||
|
||||
def Win64 : InheritableAttr {
|
||||
let Spellings = [Declspec<"w64">];
|
||||
}
|
||||
|
||||
def Ptr32 : InheritableAttr {
|
||||
let Spellings = [Declspec<"__ptr32">];
|
||||
}
|
||||
|
||||
def Ptr64 : InheritableAttr {
|
||||
let Spellings = [Declspec<"__ptr64">];
|
||||
}
|
||||
|
||||
def SingleInheritance : InheritableAttr {
|
||||
let Spellings = [Declspec<"__single_inheritance">];
|
||||
}
|
||||
|
||||
def MultipleInheritance : InheritableAttr {
|
||||
let Spellings = [Declspec<"__multiple_inheritance">];
|
||||
}
|
||||
|
||||
def VirtualInheritance : InheritableAttr {
|
||||
let Spellings = [Declspec<"__virtual_inheritance">];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,9 +6,10 @@
|
|||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the attr::Kind enum
|
||||
//
|
||||
///
|
||||
/// \file
|
||||
/// \brief Defines the clang::attr::Kind enum.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ATTRKINDS_H
|
||||
|
|
@ -18,7 +19,7 @@ namespace clang {
|
|||
|
||||
namespace attr {
|
||||
|
||||
// Kind - This is a list of all the recognized kinds of attributes.
|
||||
// \brief A list of all the recognized kinds of attributes.
|
||||
enum Kind {
|
||||
#define ATTR(X) X,
|
||||
#define LAST_INHERITABLE_ATTR(X) X, LAST_INHERITABLE = X,
|
||||
|
|
|
|||
|
|
@ -33,7 +33,8 @@
|
|||
// H -> SEL
|
||||
// a -> __builtin_va_list
|
||||
// A -> "reference" to __builtin_va_list
|
||||
// V -> Vector, following num elements and a base type.
|
||||
// V -> Vector, followed by the number of elements and the base type.
|
||||
// E -> ext_vector, followed by the number of elements and the base type.
|
||||
// X -> _Complex, followed by the base type.
|
||||
// Y -> ptrdiff_t
|
||||
// P -> FILE
|
||||
|
|
@ -475,6 +476,7 @@ BUILTIN(__builtin___vprintf_chk, "iicC*a", "FP:1:")
|
|||
|
||||
BUILTIN(__builtin_expect, "LiLiLi" , "nc")
|
||||
BUILTIN(__builtin_prefetch, "vvC*.", "nc")
|
||||
BUILTIN(__builtin_readcyclecounter, "ULLi", "n")
|
||||
BUILTIN(__builtin_trap, "v", "nr")
|
||||
BUILTIN(__builtin_unreachable, "v", "nr")
|
||||
BUILTIN(__builtin_shufflevector, "v." , "nc")
|
||||
|
|
@ -725,6 +727,10 @@ LIBBUILTIN(strndup, "c*cC*z", "f", "string.h", ALL_LANGUAGES)
|
|||
LIBBUILTIN(index, "c*cC*i", "f", "strings.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(rindex, "c*cC*i", "f", "strings.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(bzero, "vv*z", "f", "strings.h", ALL_LANGUAGES)
|
||||
// In some systems str[n]casejmp is a macro that expands to _str[n]icmp.
|
||||
// We undefine then here to avoid wrong name.
|
||||
#undef strcasecmp
|
||||
#undef strncasecmp
|
||||
LIBBUILTIN(strcasecmp, "icC*cC*", "f", "strings.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(strncasecmp, "icC*cC*z", "f", "strings.h", ALL_LANGUAGES)
|
||||
// POSIX unistd.h
|
||||
|
|
@ -804,33 +810,85 @@ LIBBUILTIN(NSLog, "vG.", "fp:0:", "Foundation/NSObjCRuntime.h", OBJC_LANG)
|
|||
LIBBUILTIN(NSLogv, "vGa", "fP:0:", "Foundation/NSObjCRuntime.h", OBJC_LANG)
|
||||
|
||||
// Builtin math library functions
|
||||
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(acos, "dd", "fe", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(acosl, "LdLd", "fe", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(acosf, "ff", "fe", "math.h", ALL_LANGUAGES)
|
||||
|
||||
LIBBUILTIN(sqrt, "dd", "fe", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(sqrtl, "LdLd", "fe", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(sqrtf, "ff", "fe", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(asin, "dd", "fe", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(asinl, "LdLd", "fe", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(asinf, "ff", "fe", "math.h", ALL_LANGUAGES)
|
||||
|
||||
LIBBUILTIN(sin, "dd", "fe", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(sinl, "LdLd", "fe", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(sinf, "ff", "fe", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(atan, "dd", "fe", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(atanl, "LdLd", "fe", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(atanf, "ff", "fe", "math.h", ALL_LANGUAGES)
|
||||
|
||||
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(cos, "dd", "fe", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(cosl, "LdLd", "fe", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(cosf, "ff", "fe", "math.h", ALL_LANGUAGES)
|
||||
|
||||
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(floor, "dd", "fe", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(floorl, "LdLd", "fe", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(floorf, "ff", "fe", "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(fmin, "ddd", "fe", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(fminl, "LdLdLd", "fe", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(fminf, "fff", "fe", "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(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(sin, "dd", "fe", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(sinl, "LdLd", "fe", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(sinf, "ff", "fe", "math.h", ALL_LANGUAGES)
|
||||
|
||||
LIBBUILTIN(sqrt, "dd", "fe", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(sqrtl, "LdLd", "fe", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(sqrtf, "ff", "fe", "math.h", ALL_LANGUAGES)
|
||||
|
||||
LIBBUILTIN(tan, "dd", "fe", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(tanl, "LdLd", "fe", "math.h", ALL_LANGUAGES)
|
||||
LIBBUILTIN(tanf, "ff", "fe", "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)
|
||||
// FIXME: Also declare NSConcreteGlobalBlock and NSConcreteStackBlock.
|
||||
|
||||
// Annotation function
|
||||
BUILTIN(__builtin_annotation, "UiUicC*", "nc")
|
||||
BUILTIN(__builtin_annotation, "v.", "tn")
|
||||
|
||||
#undef BUILTIN
|
||||
#undef LIBBUILTIN
|
||||
|
|
|
|||
|
|
@ -6,10 +6,11 @@
|
|||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines enum values for all the target-independent builtin
|
||||
// functions.
|
||||
//
|
||||
///
|
||||
/// \file
|
||||
/// \brief Defines enum values for all the target-independent builtin
|
||||
/// functions.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_BASIC_BUILTINS_H
|
||||
|
|
@ -56,7 +57,7 @@ struct Info {
|
|||
bool operator!=(const Info &RHS) const { return !(*this == RHS); }
|
||||
};
|
||||
|
||||
/// Builtin::Context - This holds information about target-independent and
|
||||
/// \brief Holds information about both target-independent and
|
||||
/// target-specific builtins, allowing easy queries by clients.
|
||||
class Context {
|
||||
const Info *TSRecords;
|
||||
|
|
@ -67,7 +68,7 @@ public:
|
|||
/// \brief Perform target-specific initialization
|
||||
void InitializeTarget(const TargetInfo &Target);
|
||||
|
||||
/// InitializeBuiltins - Mark the identifiers for all the builtins with their
|
||||
/// \brief Mark the identifiers for all the builtins with their
|
||||
/// appropriate builtin ID # and mark any non-portable builtin identifiers as
|
||||
/// such.
|
||||
void InitializeBuiltins(IdentifierTable &Table, const LangOptions& LangOpts);
|
||||
|
|
@ -76,39 +77,39 @@ public:
|
|||
void GetBuiltinNames(SmallVectorImpl<const char *> &Names,
|
||||
bool NoBuiltins);
|
||||
|
||||
/// Builtin::GetName - Return the identifier name for the specified builtin,
|
||||
/// \brief Return the identifier name for the specified builtin,
|
||||
/// e.g. "__builtin_abs".
|
||||
const char *GetName(unsigned ID) const {
|
||||
return GetRecord(ID).Name;
|
||||
}
|
||||
|
||||
/// GetTypeString - Get the type descriptor string for the specified builtin.
|
||||
/// \brief Get the type descriptor string for the specified builtin.
|
||||
const char *GetTypeString(unsigned ID) const {
|
||||
return GetRecord(ID).Type;
|
||||
}
|
||||
|
||||
/// isConst - Return true if this function has no side effects and doesn't
|
||||
/// \brief Return true if this function has no side effects and doesn't
|
||||
/// read memory.
|
||||
bool isConst(unsigned ID) const {
|
||||
return strchr(GetRecord(ID).Attributes, 'c') != 0;
|
||||
}
|
||||
|
||||
/// isNoThrow - Return true if we know this builtin never throws an exception.
|
||||
/// \brief Return true if we know this builtin never throws an exception.
|
||||
bool isNoThrow(unsigned ID) const {
|
||||
return strchr(GetRecord(ID).Attributes, 'n') != 0;
|
||||
}
|
||||
|
||||
/// isNoReturn - Return true if we know this builtin never returns.
|
||||
/// \brief Return true if we know this builtin never returns.
|
||||
bool isNoReturn(unsigned ID) const {
|
||||
return strchr(GetRecord(ID).Attributes, 'r') != 0;
|
||||
}
|
||||
|
||||
/// isReturnsTwice - Return true if we know this builtin can return twice.
|
||||
/// \brief Return true if we know this builtin can return twice.
|
||||
bool isReturnsTwice(unsigned ID) const {
|
||||
return strchr(GetRecord(ID).Attributes, 'j') != 0;
|
||||
}
|
||||
|
||||
/// isLibFunction - Return true if this is a builtin for a libc/libm function,
|
||||
/// \brief Return true if this is a builtin for a libc/libm function,
|
||||
/// with a "__builtin_" prefix (e.g. __builtin_abs).
|
||||
bool isLibFunction(unsigned ID) const {
|
||||
return strchr(GetRecord(ID).Attributes, 'F') != 0;
|
||||
|
|
@ -146,10 +147,10 @@ public:
|
|||
/// argument and whether this function as a va_list argument.
|
||||
bool isScanfLike(unsigned ID, unsigned &FormatIdx, bool &HasVAListArg);
|
||||
|
||||
/// isConstWithoutErrno - Return true if this function has no side
|
||||
/// effects and doesn't read memory, except for possibly errno. Such
|
||||
/// functions can be const when the MathErrno lang option is
|
||||
/// disabled.
|
||||
/// \brief Return true if this function has no side effects and doesn't
|
||||
/// read memory, except for possibly errno.
|
||||
///
|
||||
/// Such functions can be const when the MathErrno lang option is disabled.
|
||||
bool isConstWithoutErrno(unsigned ID) const {
|
||||
return strchr(GetRecord(ID).Attributes, 'e') != 0;
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue