Vendor import of clang trunk r321017:

https://llvm.org/svn/llvm-project/cfe/trunk@321017
This commit is contained in:
Dimitry Andric 2017-12-18 20:11:37 +00:00
parent 75c3240472
commit 461a67fa15
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/vendor/clang/dist/; revision=326941
svn path=/vendor/clang/clang-trunk-r321017/; revision=326942; tag=vendor/clang/clang-trunk-r321017
2274 changed files with 149229 additions and 54672 deletions

View File

@ -1,4 +1,4 @@
{
"project_id" : "clang",
"repository.callsign" : "C",
"conduit_uri" : "https://reviews.llvm.org/"
}

View File

@ -132,6 +132,9 @@ Please install Python or specify the PYTHON_EXECUTABLE CMake variable.")
if(EXISTS ${LLVM_MAIN_SRC_DIR}/utils/lit/lit.py)
# Note: path not really used, except for checking if lit was found
set(LLVM_LIT ${LLVM_MAIN_SRC_DIR}/utils/lit/lit.py)
if(EXISTS ${LLVM_MAIN_SRC_DIR}/utils/llvm-lit)
add_subdirectory(${LLVM_MAIN_SRC_DIR}/utils/llvm-lit utils/llvm-lit)
endif()
if(NOT LLVM_UTILS_PROVIDED)
add_subdirectory(${LLVM_MAIN_SRC_DIR}/utils/FileCheck utils/FileCheck)
add_subdirectory(${LLVM_MAIN_SRC_DIR}/utils/count utils/count)
@ -181,13 +184,16 @@ endif()
# we can include cmake files from this directory.
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules")
find_package(LibXml2 2.5.3 QUIET)
if (LIBXML2_FOUND)
set(CLANG_HAVE_LIBXML 1)
# Don't look for libxml if we're using MSan, since uninstrumented third party
# code may call MSan interceptors like strlen, leading to false positives.
if(NOT LLVM_USE_SANITIZER MATCHES "Memory.*")
set (LIBXML2_FOUND 0)
find_package(LibXml2 2.5.3 QUIET)
if (LIBXML2_FOUND)
set(CLANG_HAVE_LIBXML 1)
endif()
endif()
find_package(Z3 4.5)
include(CheckIncludeFile)
check_include_file(sys/resource.h CLANG_HAVE_RLIMITS)
@ -229,9 +235,24 @@ if (NOT(CLANG_DEFAULT_RTLIB STREQUAL "" OR
"Default runtime library to use (\"libgcc\" or \"compiler-rt\", empty for platform default)" FORCE)
endif()
set(CLANG_DEFAULT_OBJCOPY "objcopy" CACHE STRING
"Default objcopy executable to use.")
set(CLANG_DEFAULT_OPENMP_RUNTIME "libomp" CACHE STRING
"Default OpenMP runtime used by -fopenmp.")
# OpenMP offloading requires at least sm_35 because we use shuffle instructions
# to generate efficient code for reductions and the atomicMax instruction on
# 64-bit integers in the implementation of conditional lastprivate.
set(CLANG_OPENMP_NVPTX_DEFAULT_ARCH "sm_35" CACHE STRING
"Default architecture for OpenMP offloading to Nvidia GPUs.")
string(REGEX MATCH "^sm_([0-9]+)$" MATCHED_ARCH "${CLANG_OPENMP_NVPTX_DEFAULT_ARCH}")
if (NOT DEFINED MATCHED_ARCH OR "${CMAKE_MATCH_1}" LESS 35)
message(WARNING "Resetting default architecture for OpenMP offloading to Nvidia GPUs to sm_35")
set(CLANG_OPENMP_NVPTX_DEFAULT_ARCH "sm_35" CACHE STRING
"Default architecture for OpenMP offloading to Nvidia GPUs." FORCE)
endif()
set(CLANG_VENDOR ${PACKAGE_VENDOR} CACHE STRING
"Vendor-specific text for showing with version information.")
@ -376,11 +397,14 @@ option(CLANG_ENABLE_STATIC_ANALYZER "Build static analyzer." ON)
option(CLANG_ANALYZER_BUILD_Z3
"Build the static analyzer with the Z3 constraint manager." OFF)
option(CLANG_ENABLE_PROTO_FUZZER "Build Clang protobuf fuzzer." OFF)
if(NOT CLANG_ENABLE_STATIC_ANALYZER AND (CLANG_ENABLE_ARCMT OR CLANG_ANALYZER_BUILD_Z3))
message(FATAL_ERROR "Cannot disable static analyzer while enabling ARCMT or Z3")
endif()
if(CLANG_ANALYZER_BUILD_Z3)
find_package(Z3 4.5)
if(Z3_FOUND)
set(CLANG_ANALYZER_WITH_Z3 1)
else()
@ -411,7 +435,16 @@ add_subdirectory(include)
# All targets below may depend on all tablegen'd files.
get_property(CLANG_TABLEGEN_TARGETS GLOBAL PROPERTY CLANG_TABLEGEN_TARGETS)
list(APPEND LLVM_COMMON_DEPENDS ${CLANG_TABLEGEN_TARGETS})
add_custom_target(clang-tablegen-targets DEPENDS ${CLANG_TABLEGEN_TARGETS})
set_target_properties(clang-tablegen-targets PROPERTIES FOLDER "Misc")
list(APPEND LLVM_COMMON_DEPENDS clang-tablegen-targets)
# Force target to be built as soon as possible. Clang modules builds depend
# header-wise on it as they ship all headers from the umbrella folders. Building
# an entire module might include header, which depends on intrinsics_gen.
if(LLVM_ENABLE_MODULES AND NOT CLANG_BUILT_STANDALONE)
list(APPEND LLVM_COMMON_DEPENDS intrinsics_gen)
endif()
add_subdirectory(lib)
add_subdirectory(tools)
@ -508,8 +541,8 @@ if (CLANG_ENABLE_BOOTSTRAP)
set(NEXT_CLANG_STAGE ${NEXT_CLANG_STAGE}-instrumented)
endif()
message(STATUS "Setting next clang stage to: ${NEXT_CLANG_STAGE}")
set(STAMP_DIR ${CMAKE_CURRENT_BINARY_DIR}/${NEXT_CLANG_STAGE}-stamps/)
set(BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/${NEXT_CLANG_STAGE}-bins/)
@ -571,7 +604,9 @@ if (CLANG_ENABLE_BOOTSTRAP)
LLVM_BINUTILS_INCDIR
CLANG_REPOSITORY_STRING
CMAKE_MAKE_PROGRAM
CMAKE_OSX_ARCHITECTURES)
CMAKE_OSX_ARCHITECTURES
LLVM_ENABLE_PROJECTS
LLVM_ENABLE_RUNTIMES)
# We don't need to depend on compiler-rt if we're building instrumented
# because the next stage will use the same compiler used to build this stage.
@ -621,7 +656,7 @@ if (CLANG_ENABLE_BOOTSTRAP)
foreach(variableName ${variableNames})
if(variableName MATCHES "^BOOTSTRAP_")
string(SUBSTRING ${variableName} 10 -1 varName)
string(REPLACE ";" "\;" value "${${variableName}}")
string(REPLACE ";" "|" value "${${variableName}}")
list(APPEND PASSTHROUGH_VARIABLES
-D${varName}=${value})
endif()
@ -637,7 +672,7 @@ if (CLANG_ENABLE_BOOTSTRAP)
if("${${variableName}}" STREQUAL "")
set(value "")
else()
string(REPLACE ";" "\;" value ${${variableName}})
string(REPLACE ";" "|" value "${${variableName}}")
endif()
list(APPEND PASSTHROUGH_VARIABLES
-D${variableName}=${value})
@ -665,6 +700,7 @@ if (CLANG_ENABLE_BOOTSTRAP)
USES_TERMINAL_CONFIGURE 1
USES_TERMINAL_BUILD 1
USES_TERMINAL_INSTALL 1
LIST_SEPARATOR |
)
# exclude really-install from main target

View File

@ -25,6 +25,10 @@ N: Eric Christopher
E: echristo@gmail.com
D: Debug Information, inline assembly
N: Devin Coughlin
E: dcoughlin@apple.com
D: Clang Static Analyzer
N: Doug Gregor
E: dgregor@apple.com
D: Emeritus owner
@ -41,10 +45,6 @@ N: Anton Korobeynikov
E: anton@korobeynikov.info
D: Exception handling, Windows codegen, ARM EABI
N: Anna Zaks
E: ganna@apple.com
D: Clang Static Analyzer
N: John McCall
E: rjmccall@apple.com
D: Clang LLVM IR generation

View File

@ -13,10 +13,10 @@ different source-level tools. One example of this is the Clang Static Analyzer.
If you're interested in more (including how to build Clang) it is best to read
the relevant web sites. Here are some pointers:
Information on Clang: http://clang.llvm.org/
Building and using Clang: http://clang.llvm.org/get_started.html
Clang Static Analyzer: http://clang-analyzer.llvm.org/
Information on the LLVM project: http://llvm.org/
Information on Clang: http://clang.llvm.org/
Building and using Clang: http://clang.llvm.org/get_started.html
Clang Static Analyzer: http://clang-analyzer.llvm.org/
Information on the LLVM project: http://llvm.org/
If you have questions or comments about Clang, a great place to discuss them is
on the Clang development mailing list:
@ -24,3 +24,4 @@ on the Clang development mailing list:
If you find a bug in Clang, please file it in the LLVM bug tracker:
http://llvm.org/bugs/

View File

@ -5,11 +5,12 @@
This directory implements Python bindings for Clang.
You may need to alter LD_LIBRARY_PATH so that the Clang library can be
found. The unit tests are designed to be run with 'nosetests'. For example:
found. The unit tests are designed to be run with any standard test
runner. For example:
--
$ env PYTHONPATH=$(echo ~/llvm/tools/clang/bindings/python/) \
LD_LIBRARY_PATH=$(llvm-config --libdir) \
nosetests -v
python -m unittest discover -v
tests.cindex.test_index.test_create ... ok
...

View File

@ -94,6 +94,9 @@ def from_param(cls, param):
return cls(param)
if isinstance(param, bytes):
return cls(param)
if param is None:
# Support passing null to C functions expecting char arrays
return None
raise TypeError("Cannot convert '{}' to '{}'".format(type(param).__name__, cls.__name__))
@staticmethod
@ -1476,6 +1479,12 @@ def is_virtual_method(self):
"""
return conf.lib.clang_CXXMethod_isVirtual(self)
def is_abstract_record(self):
"""Returns True if the cursor refers to a C++ record declaration
that has pure virtual member functions.
"""
return conf.lib.clang_CXXRecord_isAbstract(self)
def is_scoped_enum(self):
"""Returns True if the cursor refers to a scoped enum declaration.
"""
@ -1548,6 +1557,22 @@ def location(self):
return self._loc
@property
def linkage(self):
"""Return the linkage of this cursor."""
if not hasattr(self, '_linkage'):
self._linkage = conf.lib.clang_getCursorLinkage(self)
return LinkageKind.from_id(self._linkage)
@property
def tls_kind(self):
"""Return the thread-local storage (TLS) kind of this cursor."""
if not hasattr(self, '_tls_kind'):
self._tls_kind = conf.lib.clang_getCursorTLSKind(self)
return TLSKind.from_id(self._tls_kind)
@property
def extent(self):
"""
@ -1570,6 +1595,16 @@ def storage_class(self):
return StorageClass.from_id(self._storage_class)
@property
def availability(self):
"""
Retrieves the availability of the entity pointed at by the cursor.
"""
if not hasattr(self, '_availability'):
self._availability = conf.lib.clang_getCursorAvailability(self)
return AvailabilityKind.from_id(self._availability)
@property
def access_specifier(self):
"""
@ -1907,6 +1942,24 @@ def __repr__(self):
StorageClass.AUTO = StorageClass(6)
StorageClass.REGISTER = StorageClass(7)
### Availability Kinds ###
class AvailabilityKind(BaseEnumeration):
"""
Describes the availability of an entity.
"""
# The unique kind objects, indexed by id.
_kinds = []
_name_map = None
def __repr__(self):
return 'AvailabilityKind.%s' % (self.name,)
AvailabilityKind.AVAILABLE = AvailabilityKind(0)
AvailabilityKind.DEPRECATED = AvailabilityKind(1)
AvailabilityKind.NOT_AVAILABLE = AvailabilityKind(2)
AvailabilityKind.NOT_ACCESSIBLE = AvailabilityKind(3)
### C++ access specifiers ###
@ -2061,6 +2114,42 @@ def __repr__(self):
RefQualifierKind.LVALUE = RefQualifierKind(1)
RefQualifierKind.RVALUE = RefQualifierKind(2)
class LinkageKind(BaseEnumeration):
"""Describes the kind of linkage of a cursor."""
# The unique kind objects, indexed by id.
_kinds = []
_name_map = None
def from_param(self):
return self.value
def __repr__(self):
return 'LinkageKind.%s' % (self.name,)
LinkageKind.INVALID = LinkageKind(0)
LinkageKind.NO_LINKAGE = LinkageKind(1)
LinkageKind.INTERNAL = LinkageKind(2)
LinkageKind.UNIQUE_EXTERNAL = LinkageKind(3)
LinkageKind.EXTERNAL = LinkageKind(4)
class TLSKind(BaseEnumeration):
"""Describes the kind of thread-local storage (TLS) of a cursor."""
# The unique kind objects, indexed by id.
_kinds = []
_name_map = None
def from_param(self):
return self.value
def __repr__(self):
return 'TLSKind.%s' % (self.name,)
TLSKind.NONE = TLSKind(0)
TLSKind.DYNAMIC = TLSKind(1)
TLSKind.STATIC = TLSKind(2)
class Type(Structure):
"""
The type of an element in the abstract syntax tree.
@ -3191,6 +3280,7 @@ def extent(self):
def cursor(self):
"""The Cursor this Token corresponds to."""
cursor = Cursor()
cursor._tu = self._tu
conf.lib.clang_annotateTokens(self._tu, byref(self), 1, byref(cursor))
@ -3317,6 +3407,10 @@ def cursor(self):
[Cursor],
bool),
("clang_CXXRecord_isAbstract",
[Cursor],
bool),
("clang_EnumDecl_isScoped",
[Cursor],
bool),
@ -3438,6 +3532,10 @@ def cursor(self):
[TranslationUnit, SourceLocation],
Cursor),
("clang_getCursorAvailability",
[Cursor],
c_int),
("clang_getCursorDefinition",
[Cursor],
Cursor,
@ -4053,6 +4151,7 @@ def register_enumerations():
register_enumerations()
__all__ = [
'AvailabilityKind',
'Config',
'CodeCompletionResults',
'CompilationDatabase',
@ -4064,8 +4163,10 @@ def register_enumerations():
'File',
'FixIt',
'Index',
'LinkageKind',
'SourceLocation',
'SourceRange',
'TLSKind',
'TokenKind',
'Token',
'TranslationUnitLoadError',

View File

@ -6,10 +6,14 @@
from .util import get_cursor
from .util import get_tu
def test_access_specifiers():
"""Ensure that C++ access specifiers are available on cursors"""
import unittest
tu = get_tu("""
class TestAccessSpecifiers(unittest.TestCase):
def test_access_specifiers(self):
"""Ensure that C++ access specifiers are available on cursors"""
tu = get_tu("""
class test_class {
public:
void public_member_function();
@ -20,15 +24,14 @@ class test_class {
};
""", lang = 'cpp')
test_class = get_cursor(tu, "test_class")
assert test_class.access_specifier == AccessSpecifier.INVALID;
test_class = get_cursor(tu, "test_class")
self.assertEqual(test_class.access_specifier, AccessSpecifier.INVALID)
public = get_cursor(tu.cursor, "public_member_function")
assert public.access_specifier == AccessSpecifier.PUBLIC
public = get_cursor(tu.cursor, "public_member_function")
self.assertEqual(public.access_specifier, AccessSpecifier.PUBLIC)
protected = get_cursor(tu.cursor, "protected_member_function")
assert protected.access_specifier == AccessSpecifier.PROTECTED
private = get_cursor(tu.cursor, "private_member_function")
assert private.access_specifier == AccessSpecifier.PRIVATE
protected = get_cursor(tu.cursor, "protected_member_function")
self.assertEqual(protected.access_specifier, AccessSpecifier.PROTECTED)
private = get_cursor(tu.cursor, "private_member_function")
self.assertEqual(private.access_specifier, AccessSpecifier.PRIVATE)

View File

@ -4,114 +4,116 @@
from clang.cindex import CompileCommand
import os
import gc
import unittest
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)
class TestCDB(unittest.TestCase):
def test_create_fail(self):
"""Check we fail loading a database with an assertion"""
path = os.path.dirname(__file__)
with self.assertRaises(CompilationDatabaseError) as cm:
cdb = CompilationDatabase.fromDirectory(path)
e = cm.exception
self.assertEqual(e.cdb_error,
CompilationDatabaseError.ERROR_CANNOTLOADDATABASE)
def test_lookup_fail():
"""Check file lookup failure"""
cdb = CompilationDatabase.fromDirectory(kInputsDir)
assert cdb.getCompileCommands('file_do_not_exist.cpp') == None
def test_create(self):
"""Check we can load a compilation database"""
cdb = CompilationDatabase.fromDirectory(kInputsDir)
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_lookup_fail(self):
"""Check file lookup failure"""
cdb = CompilationDatabase.fromDirectory(kInputsDir)
self.assertIsNone(cdb.getCompileCommands('file_do_not_exist.cpp'))
def test_all_compilecommand():
"""Check we get all results from the db"""
cdb = CompilationDatabase.fromDirectory(kInputsDir)
cmds = cdb.getAllCompileCommands()
assert len(cmds) == 3
expected = [
{ 'wd': '/home/john.doe/MyProject',
'file': '/home/john.doe/MyProject/project.cpp',
'line': ['clang++', '-o', 'project.o', '-c',
'/home/john.doe/MyProject/project.cpp']},
{ 'wd': '/home/john.doe/MyProjectA',
'file': '/home/john.doe/MyProject/project2.cpp',
'line': ['clang++', '-o', 'project2.o', '-c',
'/home/john.doe/MyProject/project2.cpp']},
{ 'wd': '/home/john.doe/MyProjectB',
'file': '/home/john.doe/MyProject/project2.cpp',
'line': ['clang++', '-DFEATURE=1', '-o', 'project2-feature.o', '-c',
'/home/john.doe/MyProject/project2.cpp']},
def test_lookup_succeed(self):
"""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')
self.assertNotEqual(len(cmds), 0)
]
for i in range(len(cmds)):
assert cmds[i].directory == expected[i]['wd']
assert cmds[i].filename == expected[i]['file']
for arg, exp in zip(cmds[i].arguments, expected[i]['line']):
assert arg == exp
def test_all_compilecommand(self):
"""Check we get all results from the db"""
cdb = CompilationDatabase.fromDirectory(kInputsDir)
cmds = cdb.getAllCompileCommands()
self.assertEqual(len(cmds), 3)
expected = [
{ 'wd': '/home/john.doe/MyProject',
'file': '/home/john.doe/MyProject/project.cpp',
'line': ['clang++', '-o', 'project.o', '-c',
'/home/john.doe/MyProject/project.cpp']},
{ 'wd': '/home/john.doe/MyProjectA',
'file': '/home/john.doe/MyProject/project2.cpp',
'line': ['clang++', '-o', 'project2.o', '-c',
'/home/john.doe/MyProject/project2.cpp']},
{ 'wd': '/home/john.doe/MyProjectB',
'file': '/home/john.doe/MyProject/project2.cpp',
'line': ['clang++', '-DFEATURE=1', '-o', 'project2-feature.o', '-c',
'/home/john.doe/MyProject/project2.cpp']},
def test_1_compilecommand():
"""Check file with single compile command"""
cdb = CompilationDatabase.fromDirectory(kInputsDir)
file = '/home/john.doe/MyProject/project.cpp'
cmds = cdb.getCompileCommands(file)
assert len(cmds) == 1
assert cmds[0].directory == os.path.dirname(file)
assert cmds[0].filename == file
expected = [ 'clang++', '-o', 'project.o', '-c',
'/home/john.doe/MyProject/project.cpp']
for arg, exp in zip(cmds[0].arguments, expected):
assert arg == exp
]
for i in range(len(cmds)):
self.assertEqual(cmds[i].directory, expected[i]['wd'])
self.assertEqual(cmds[i].filename, expected[i]['file'])
for arg, exp in zip(cmds[i].arguments, expected[i]['line']):
self.assertEqual(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_1_compilecommand(self):
"""Check file with single compile command"""
cdb = CompilationDatabase.fromDirectory(kInputsDir)
file = '/home/john.doe/MyProject/project.cpp'
cmds = cdb.getCompileCommands(file)
self.assertEqual(len(cmds), 1)
self.assertEqual(cmds[0].directory, os.path.dirname(file))
self.assertEqual(cmds[0].filename, file)
expected = [ 'clang++', '-o', 'project.o', '-c',
'/home/john.doe/MyProject/project.cpp']
for arg, exp in zip(cmds[0].arguments, expected):
self.assertEqual(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_2_compilecommand(self):
"""Check file with 2 compile commands"""
cdb = CompilationDatabase.fromDirectory(kInputsDir)
cmds = cdb.getCompileCommands('/home/john.doe/MyProject/project2.cpp')
self.assertEqual(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)):
self.assertEqual(cmds[i].directory, expected[i]['wd'])
for arg, exp in zip(cmds[i].arguments, expected[i]['line']):
self.assertEqual(arg, exp)
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_compilecommand_iterator_stops(self):
"""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
self.assertLessEqual(count, 2)
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
def test_compilationDB_references(self):
"""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(self):
"""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

View File

@ -1,16 +1,20 @@
from clang.cindex import TranslationUnit
def check_completion_results(cr, expected):
assert cr is not None
assert len(cr.diagnostics) == 0
import unittest
completions = [str(c) for c in cr.results]
for c in expected:
assert c in completions
class TestCodeCompletion(unittest.TestCase):
def check_completion_results(self, cr, expected):
self.assertIsNotNone(cr)
self.assertEqual(len(cr.diagnostics), 0)
def test_code_complete():
files = [('fake.c', """
completions = [str(c) for c in cr.results]
for c in expected:
self.assertIn(c, completions)
def test_code_complete(self):
files = [('fake.c', """
/// Aaa.
int test1;
@ -22,20 +26,20 @@ def test_code_complete():
}
""")]
tu = TranslationUnit.from_source('fake.c', ['-std=c99'], unsaved_files=files,
options=TranslationUnit.PARSE_INCLUDE_BRIEF_COMMENTS_IN_CODE_COMPLETION)
tu = TranslationUnit.from_source('fake.c', ['-std=c99'], unsaved_files=files,
options=TranslationUnit.PARSE_INCLUDE_BRIEF_COMMENTS_IN_CODE_COMPLETION)
cr = tu.codeComplete('fake.c', 9, 1, unsaved_files=files, include_brief_comments=True)
cr = tu.codeComplete('fake.c', 9, 1, unsaved_files=files, include_brief_comments=True)
expected = [
"{'int', ResultType} | {'test1', TypedText} || Priority: 50 || Availability: Available || Brief comment: Aaa.",
"{'void', ResultType} | {'test2', TypedText} | {'(', LeftParen} | {')', RightParen} || Priority: 50 || Availability: Available || Brief comment: Bbb.",
"{'return', TypedText} || Priority: 40 || Availability: Available || Brief comment: None"
]
check_completion_results(cr, expected)
expected = [
"{'int', ResultType} | {'test1', TypedText} || Priority: 50 || Availability: Available || Brief comment: Aaa.",
"{'void', ResultType} | {'test2', TypedText} | {'(', LeftParen} | {')', RightParen} || Priority: 50 || Availability: Available || Brief comment: Bbb.",
"{'return', TypedText} || Priority: 40 || Availability: Available || Brief comment: None"
]
self.check_completion_results(cr, expected)
def test_code_complete_availability():
files = [('fake.cpp', """
def test_code_complete_availability(self):
files = [('fake.cpp', """
class P {
protected:
int member;
@ -52,24 +56,24 @@ class Q : public P {
}
""")]
tu = TranslationUnit.from_source('fake.cpp', ['-std=c++98'], unsaved_files=files)
tu = TranslationUnit.from_source('fake.cpp', ['-std=c++98'], unsaved_files=files)
cr = tu.codeComplete('fake.cpp', 12, 5, unsaved_files=files)
cr = tu.codeComplete('fake.cpp', 12, 5, unsaved_files=files)
expected = [
"{'const', TypedText} || Priority: 40 || Availability: Available || Brief comment: None",
"{'volatile', TypedText} || Priority: 40 || Availability: Available || Brief comment: None",
"{'operator', TypedText} || Priority: 40 || Availability: Available || Brief comment: None",
"{'P', TypedText} | {'::', Text} || Priority: 75 || Availability: Available || Brief comment: None",
"{'Q', TypedText} | {'::', Text} || Priority: 75 || Availability: Available || Brief comment: None"
]
check_completion_results(cr, expected)
expected = [
"{'const', TypedText} || Priority: 40 || Availability: Available || Brief comment: None",
"{'volatile', TypedText} || Priority: 40 || Availability: Available || Brief comment: None",
"{'operator', TypedText} || Priority: 40 || Availability: Available || Brief comment: None",
"{'P', TypedText} | {'::', Text} || Priority: 75 || Availability: Available || Brief comment: None",
"{'Q', TypedText} | {'::', Text} || Priority: 75 || Availability: Available || Brief comment: None"
]
self.check_completion_results(cr, expected)
cr = tu.codeComplete('fake.cpp', 13, 5, unsaved_files=files)
expected = [
"{'P', TypedText} | {'::', Text} || Priority: 75 || Availability: Available || Brief comment: None",
"{'P &', ResultType} | {'operator=', TypedText} | {'(', LeftParen} | {'const P &', Placeholder} | {')', RightParen} || Priority: 34 || Availability: Available || Brief comment: None",
"{'int', ResultType} | {'member', TypedText} || Priority: 35 || Availability: NotAccessible || Brief comment: None",
"{'void', ResultType} | {'~P', TypedText} | {'(', LeftParen} | {')', RightParen} || Priority: 34 || Availability: Available || Brief comment: None"
]
check_completion_results(cr, expected)
cr = tu.codeComplete('fake.cpp', 13, 5, unsaved_files=files)
expected = [
"{'P', TypedText} | {'::', Text} || Priority: 75 || Availability: Available || Brief comment: None",
"{'P &', ResultType} | {'operator=', TypedText} | {'(', LeftParen} | {'const P &', Placeholder} | {')', RightParen} || Priority: 79 || Availability: Available || Brief comment: None",
"{'int', ResultType} | {'member', TypedText} || Priority: 35 || Availability: NotAccessible || Brief comment: None",
"{'void', ResultType} | {'~P', TypedText} | {'(', LeftParen} | {')', RightParen} || Priority: 79 || Availability: Available || Brief comment: None"
]
self.check_completion_results(cr, expected)

View File

@ -1,8 +1,12 @@
from clang.cindex import TranslationUnit
from tests.cindex.util import get_cursor
def test_comment():
files = [('fake.c', """
import unittest
class TestComment(unittest.TestCase):
def test_comment(self):
files = [('fake.c', """
/// Aaa.
int test1;
@ -14,27 +18,25 @@ def test_comment():
}
""")]
# make a comment-aware TU
tu = TranslationUnit.from_source('fake.c', ['-std=c99'], unsaved_files=files,
options=TranslationUnit.PARSE_INCLUDE_BRIEF_COMMENTS_IN_CODE_COMPLETION)
test1 = get_cursor(tu, 'test1')
assert test1 is not None, "Could not find test1."
assert test1.type.is_pod()
raw = test1.raw_comment
brief = test1.brief_comment
assert raw == """/// Aaa."""
assert brief == """Aaa."""
test2 = get_cursor(tu, 'test2')
raw = test2.raw_comment
brief = test2.brief_comment
assert raw == """/// Bbb.\n/// x"""
assert brief == """Bbb. x"""
f = get_cursor(tu, 'f')
raw = f.raw_comment
brief = f.brief_comment
assert raw is None
assert brief is None
# make a comment-aware TU
tu = TranslationUnit.from_source('fake.c', ['-std=c99'], unsaved_files=files,
options=TranslationUnit.PARSE_INCLUDE_BRIEF_COMMENTS_IN_CODE_COMPLETION)
test1 = get_cursor(tu, 'test1')
self.assertIsNotNone(test1, "Could not find test1.")
self.assertTrue(test1.type.is_pod())
raw = test1.raw_comment
brief = test1.brief_comment
self.assertEqual(raw, """/// Aaa.""")
self.assertEqual(brief, """Aaa.""")
test2 = get_cursor(tu, 'test2')
raw = test2.raw_comment
brief = test2.brief_comment
self.assertEqual(raw, """/// Bbb.\n/// x""")
self.assertEqual(brief, """Bbb. x""")
f = get_cursor(tu, 'f')
raw = f.raw_comment
brief = f.brief_comment
self.assertIsNone(raw)
self.assertIsNone(brief)

View File

@ -1,6 +1,8 @@
import ctypes
import gc
import unittest
from clang.cindex import AvailabilityKind
from clang.cindex import CursorKind
from clang.cindex import TemplateArgumentKind
from clang.cindex import TranslationUnit
@ -9,6 +11,7 @@
from .util import get_cursors
from .util import get_tu
kInput = """\
struct s0 {
int a;
@ -29,257 +32,6 @@
}
"""
def test_get_children():
tu = get_tu(kInput)
it = tu.cursor.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
assert tu_nodes[0].spelling == 's0'
assert tu_nodes[0].is_definition() == True
assert tu_nodes[0].location.file.name == 't.c'
assert tu_nodes[0].location.line == 1
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
assert s0_nodes[0].kind == CursorKind.FIELD_DECL
assert s0_nodes[0].spelling == 'a'
assert s0_nodes[0].type.kind == TypeKind.INT
assert s0_nodes[1].kind == CursorKind.FIELD_DECL
assert s0_nodes[1].spelling == 'b'
assert s0_nodes[1].type.kind == TypeKind.INT
assert tu_nodes[1].kind == CursorKind.STRUCT_DECL
assert tu_nodes[1].spelling == 's1'
assert tu_nodes[1].displayname == 's1'
assert tu_nodes[1].is_definition() == False
assert tu_nodes[2].kind == CursorKind.FUNCTION_DECL
assert tu_nodes[2].spelling == 'f0'
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_const_method():
"""Ensure Cursor.is_const_method works."""
source = 'class X { void foo() const; 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_const_method()
assert not bar.is_const_method()
def test_is_converting_constructor():
"""Ensure Cursor.is_converting_constructor works."""
source = 'class X { explicit X(int); X(double); X(); };'
tu = get_tu(source, lang='cpp')
xs = get_cursors(tu, 'X')
assert len(xs) == 4
assert xs[0].kind == CursorKind.CLASS_DECL
cs = xs[1:]
assert cs[0].kind == CursorKind.CONSTRUCTOR
assert cs[1].kind == CursorKind.CONSTRUCTOR
assert cs[2].kind == CursorKind.CONSTRUCTOR
assert not cs[0].is_converting_constructor()
assert cs[1].is_converting_constructor()
assert not cs[2].is_converting_constructor()
def test_is_copy_constructor():
"""Ensure Cursor.is_copy_constructor works."""
source = 'class X { X(); X(const X&); X(X&&); };'
tu = get_tu(source, lang='cpp')
xs = get_cursors(tu, 'X')
assert xs[0].kind == CursorKind.CLASS_DECL
cs = xs[1:]
assert cs[0].kind == CursorKind.CONSTRUCTOR
assert cs[1].kind == CursorKind.CONSTRUCTOR
assert cs[2].kind == CursorKind.CONSTRUCTOR
assert not cs[0].is_copy_constructor()
assert cs[1].is_copy_constructor()
assert not cs[2].is_copy_constructor()
def test_is_default_constructor():
"""Ensure Cursor.is_default_constructor works."""
source = 'class X { X(); X(int); };'
tu = get_tu(source, lang='cpp')
xs = get_cursors(tu, 'X')
assert xs[0].kind == CursorKind.CLASS_DECL
cs = xs[1:]
assert cs[0].kind == CursorKind.CONSTRUCTOR
assert cs[1].kind == CursorKind.CONSTRUCTOR
assert cs[0].is_default_constructor()
assert not cs[1].is_default_constructor()
def test_is_move_constructor():
"""Ensure Cursor.is_move_constructor works."""
source = 'class X { X(); X(const X&); X(X&&); };'
tu = get_tu(source, lang='cpp')
xs = get_cursors(tu, 'X')
assert xs[0].kind == CursorKind.CLASS_DECL
cs = xs[1:]
assert cs[0].kind == CursorKind.CONSTRUCTOR
assert cs[1].kind == CursorKind.CONSTRUCTOR
assert cs[2].kind == CursorKind.CONSTRUCTOR
assert not cs[0].is_move_constructor()
assert not cs[1].is_move_constructor()
assert cs[2].is_move_constructor()
def test_is_default_method():
"""Ensure Cursor.is_default_method works."""
source = 'class X { X() = default; }; class Y { Y(); };'
tu = get_tu(source, lang='cpp')
xs = get_cursors(tu, 'X')
ys = get_cursors(tu, 'Y')
assert len(xs) == 2
assert len(ys) == 2
xc = xs[1]
yc = ys[1]
assert xc.is_default_method()
assert not yc.is_default_method()
def test_is_mutable_field():
"""Ensure Cursor.is_mutable_field works."""
source = 'class X { int x_; mutable int y_; };'
tu = get_tu(source, lang='cpp')
cls = get_cursor(tu, 'X')
x_ = get_cursor(tu, 'x_')
y_ = get_cursor(tu, 'y_')
assert cls is not None
assert x_ is not None
assert y_ is not None
assert not x_.is_mutable_field()
assert y_.is_mutable_field()
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_is_pure_virtual_method():
"""Ensure Cursor.is_pure_virtual_method works."""
source = 'class X { virtual void foo() = 0; virtual 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_pure_virtual_method()
assert not bar.is_pure_virtual_method()
def test_is_virtual_method():
"""Ensure Cursor.is_virtual_method works."""
source = 'class X { virtual 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_virtual_method()
assert not bar.is_virtual_method()
def test_is_scoped_enum():
"""Ensure Cursor.is_scoped_enum works."""
source = 'class X {}; enum RegularEnum {}; enum class ScopedEnum {};'
tu = get_tu(source, lang='cpp')
cls = get_cursor(tu, 'X')
regular_enum = get_cursor(tu, 'RegularEnum')
scoped_enum = get_cursor(tu, 'ScopedEnum')
assert cls is not None
assert regular_enum is not None
assert scoped_enum is not None
assert not cls.is_scoped_enum()
assert not regular_enum.is_scoped_enum()
assert scoped_enum.is_scoped_enum()
def test_underlying_type():
tu = get_tu('typedef int foo;')
typedef = get_cursor(tu, 'foo')
assert typedef is not None
assert typedef.kind.is_declaration()
underlying = typedef.underlying_typedef_type
assert underlying.kind == TypeKind.INT
kParentTest = """\
class C {
void f();
@ -287,122 +39,6 @@ class C {
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')
assert enum is not None
assert enum.kind == CursorKind.ENUM_DECL
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) == 6
assert tokens[0].spelling == 'int'
assert tokens[1].spelling == 'foo'
def test_get_arguments():
tu = get_tu('void foo(int i, int j);')
foo = get_cursor(tu, 'foo')
arguments = list(foo.get_arguments())
assert len(arguments) == 2
assert arguments[0].spelling == "i"
assert arguments[1].spelling == "j"
kTemplateArgTest = """\
template <int kInt, typename T, bool kBool>
@ -412,59 +48,505 @@ def test_get_arguments():
void foo<-7, float, true>();
"""
def test_get_num_template_arguments():
tu = get_tu(kTemplateArgTest, lang='cpp')
foos = get_cursors(tu, 'foo')
class TestCursor(unittest.TestCase):
def test_get_children(self):
tu = get_tu(kInput)
assert foos[1].get_num_template_arguments() == 3
it = tu.cursor.get_children()
tu_nodes = list(it)
def test_get_template_argument_kind():
tu = get_tu(kTemplateArgTest, lang='cpp')
foos = get_cursors(tu, 'foo')
self.assertEqual(len(tu_nodes), 3)
for cursor in tu_nodes:
self.assertIsNotNone(cursor.translation_unit)
assert foos[1].get_template_argument_kind(0) == TemplateArgumentKind.INTEGRAL
assert foos[1].get_template_argument_kind(1) == TemplateArgumentKind.TYPE
assert foos[1].get_template_argument_kind(2) == TemplateArgumentKind.INTEGRAL
self.assertNotEqual(tu_nodes[0], tu_nodes[1])
self.assertEqual(tu_nodes[0].kind, CursorKind.STRUCT_DECL)
self.assertEqual(tu_nodes[0].spelling, 's0')
self.assertEqual(tu_nodes[0].is_definition(), True)
self.assertEqual(tu_nodes[0].location.file.name, 't.c')
self.assertEqual(tu_nodes[0].location.line, 1)
self.assertEqual(tu_nodes[0].location.column, 8)
self.assertGreater(tu_nodes[0].hash, 0)
self.assertIsNotNone(tu_nodes[0].translation_unit)
def test_get_template_argument_type():
tu = get_tu(kTemplateArgTest, lang='cpp')
foos = get_cursors(tu, 'foo')
s0_nodes = list(tu_nodes[0].get_children())
self.assertEqual(len(s0_nodes), 2)
self.assertEqual(s0_nodes[0].kind, CursorKind.FIELD_DECL)
self.assertEqual(s0_nodes[0].spelling, 'a')
self.assertEqual(s0_nodes[0].type.kind, TypeKind.INT)
self.assertEqual(s0_nodes[1].kind, CursorKind.FIELD_DECL)
self.assertEqual(s0_nodes[1].spelling, 'b')
self.assertEqual(s0_nodes[1].type.kind, TypeKind.INT)
assert foos[1].get_template_argument_type(1).kind == TypeKind.FLOAT
self.assertEqual(tu_nodes[1].kind, CursorKind.STRUCT_DECL)
self.assertEqual(tu_nodes[1].spelling, 's1')
self.assertEqual(tu_nodes[1].displayname, 's1')
self.assertEqual(tu_nodes[1].is_definition(), False)
def test_get_template_argument_value():
tu = get_tu(kTemplateArgTest, lang='cpp')
foos = get_cursors(tu, 'foo')
self.assertEqual(tu_nodes[2].kind, CursorKind.FUNCTION_DECL)
self.assertEqual(tu_nodes[2].spelling, 'f0')
self.assertEqual(tu_nodes[2].displayname, 'f0(int, int)')
self.assertEqual(tu_nodes[2].is_definition(), True)
assert foos[1].get_template_argument_value(0) == -7
assert foos[1].get_template_argument_value(2) == True
def test_references(self):
"""Ensure that references to TranslationUnit are kept."""
tu = get_tu('int x;')
cursors = list(tu.cursor.get_children())
self.assertGreater(len(cursors), 0)
def test_get_template_argument_unsigned_value():
tu = get_tu(kTemplateArgTest, lang='cpp')
foos = get_cursors(tu, 'foo')
cursor = cursors[0]
self.assertIsInstance(cursor.translation_unit, TranslationUnit)
assert foos[1].get_template_argument_unsigned_value(0) == 2 ** 32 - 7
assert foos[1].get_template_argument_unsigned_value(2) == True
# Delete reference to TU and perform a full GC.
del tu
gc.collect()
self.assertIsInstance(cursor.translation_unit, TranslationUnit)
def test_referenced():
tu = get_tu('void foo(); void bar() { foo(); }')
foo = get_cursor(tu, 'foo')
bar = get_cursor(tu, 'bar')
for c in bar.get_children():
if c.kind == CursorKind.CALL_EXPR:
assert c.referenced.spelling == foo.spelling
break
# If the TU was destroyed, this should cause a segfault.
parent = cursor.semantic_parent
def test_mangled_name():
kInputForMangling = """\
int foo(int, int);
"""
tu = get_tu(kInputForMangling, lang='cpp')
foo = get_cursor(tu, 'foo')
def test_canonical(self):
source = 'struct X; struct X; struct X { int member; };'
tu = get_tu(source)
# Since libclang does not link in targets, we cannot pass a triple to it
# and force the target. To enable this test to pass on all platforms, accept
# all valid manglings.
# [c-index-test handles this by running the source through clang, emitting
# an AST file and running libclang on that AST file]
assert foo.mangled_name in ('_Z3fooii', '__Z3fooii', '?foo@@YAHHH')
cursors = []
for cursor in tu.cursor.get_children():
if cursor.spelling == 'X':
cursors.append(cursor)
self.assertEqual(len(cursors), 3)
self.assertEqual(cursors[1].canonical, cursors[2].canonical)
def test_is_const_method(self):
"""Ensure Cursor.is_const_method works."""
source = 'class X { void foo() const; void bar(); };'
tu = get_tu(source, lang='cpp')
cls = get_cursor(tu, 'X')
foo = get_cursor(tu, 'foo')
bar = get_cursor(tu, 'bar')
self.assertIsNotNone(cls)
self.assertIsNotNone(foo)
self.assertIsNotNone(bar)
self.assertTrue(foo.is_const_method())
self.assertFalse(bar.is_const_method())
def test_is_converting_constructor(self):
"""Ensure Cursor.is_converting_constructor works."""
source = 'class X { explicit X(int); X(double); X(); };'
tu = get_tu(source, lang='cpp')
xs = get_cursors(tu, 'X')
self.assertEqual(len(xs), 4)
self.assertEqual(xs[0].kind, CursorKind.CLASS_DECL)
cs = xs[1:]
self.assertEqual(cs[0].kind, CursorKind.CONSTRUCTOR)
self.assertEqual(cs[1].kind, CursorKind.CONSTRUCTOR)
self.assertEqual(cs[2].kind, CursorKind.CONSTRUCTOR)
self.assertFalse(cs[0].is_converting_constructor())
self.assertTrue(cs[1].is_converting_constructor())
self.assertFalse(cs[2].is_converting_constructor())
def test_is_copy_constructor(self):
"""Ensure Cursor.is_copy_constructor works."""
source = 'class X { X(); X(const X&); X(X&&); };'
tu = get_tu(source, lang='cpp')
xs = get_cursors(tu, 'X')
self.assertEqual(xs[0].kind, CursorKind.CLASS_DECL)
cs = xs[1:]
self.assertEqual(cs[0].kind, CursorKind.CONSTRUCTOR)
self.assertEqual(cs[1].kind, CursorKind.CONSTRUCTOR)
self.assertEqual(cs[2].kind, CursorKind.CONSTRUCTOR)
self.assertFalse(cs[0].is_copy_constructor())
self.assertTrue(cs[1].is_copy_constructor())
self.assertFalse(cs[2].is_copy_constructor())
def test_is_default_constructor(self):
"""Ensure Cursor.is_default_constructor works."""
source = 'class X { X(); X(int); };'
tu = get_tu(source, lang='cpp')
xs = get_cursors(tu, 'X')
self.assertEqual(xs[0].kind, CursorKind.CLASS_DECL)
cs = xs[1:]
self.assertEqual(cs[0].kind, CursorKind.CONSTRUCTOR)
self.assertEqual(cs[1].kind, CursorKind.CONSTRUCTOR)
self.assertTrue(cs[0].is_default_constructor())
self.assertFalse(cs[1].is_default_constructor())
def test_is_move_constructor(self):
"""Ensure Cursor.is_move_constructor works."""
source = 'class X { X(); X(const X&); X(X&&); };'
tu = get_tu(source, lang='cpp')
xs = get_cursors(tu, 'X')
self.assertEqual(xs[0].kind, CursorKind.CLASS_DECL)
cs = xs[1:]
self.assertEqual(cs[0].kind, CursorKind.CONSTRUCTOR)
self.assertEqual(cs[1].kind, CursorKind.CONSTRUCTOR)
self.assertEqual(cs[2].kind, CursorKind.CONSTRUCTOR)
self.assertFalse(cs[0].is_move_constructor())
self.assertFalse(cs[1].is_move_constructor())
self.assertTrue(cs[2].is_move_constructor())
def test_is_default_method(self):
"""Ensure Cursor.is_default_method works."""
source = 'class X { X() = default; }; class Y { Y(); };'
tu = get_tu(source, lang='cpp')
xs = get_cursors(tu, 'X')
ys = get_cursors(tu, 'Y')
self.assertEqual(len(xs), 2)
self.assertEqual(len(ys), 2)
xc = xs[1]
yc = ys[1]
self.assertTrue(xc.is_default_method())
self.assertFalse(yc.is_default_method())
def test_is_mutable_field(self):
"""Ensure Cursor.is_mutable_field works."""
source = 'class X { int x_; mutable int y_; };'
tu = get_tu(source, lang='cpp')
cls = get_cursor(tu, 'X')
x_ = get_cursor(tu, 'x_')
y_ = get_cursor(tu, 'y_')
self.assertIsNotNone(cls)
self.assertIsNotNone(x_)
self.assertIsNotNone(y_)
self.assertFalse(x_.is_mutable_field())
self.assertTrue(y_.is_mutable_field())
def test_is_static_method(self):
"""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')
self.assertIsNotNone(cls)
self.assertIsNotNone(foo)
self.assertIsNotNone(bar)
self.assertTrue(foo.is_static_method())
self.assertFalse(bar.is_static_method())
def test_is_pure_virtual_method(self):
"""Ensure Cursor.is_pure_virtual_method works."""
source = 'class X { virtual void foo() = 0; virtual void bar(); };'
tu = get_tu(source, lang='cpp')
cls = get_cursor(tu, 'X')
foo = get_cursor(tu, 'foo')
bar = get_cursor(tu, 'bar')
self.assertIsNotNone(cls)
self.assertIsNotNone(foo)
self.assertIsNotNone(bar)
self.assertTrue(foo.is_pure_virtual_method())
self.assertFalse(bar.is_pure_virtual_method())
def test_is_virtual_method(self):
"""Ensure Cursor.is_virtual_method works."""
source = 'class X { virtual 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')
self.assertIsNotNone(cls)
self.assertIsNotNone(foo)
self.assertIsNotNone(bar)
self.assertTrue(foo.is_virtual_method())
self.assertFalse(bar.is_virtual_method())
def test_is_abstract_record(self):
"""Ensure Cursor.is_abstract_record works."""
source = 'struct X { virtual void x() = 0; }; struct Y : X { void x(); };'
tu = get_tu(source, lang='cpp')
cls = get_cursor(tu, 'X')
self.assertTrue(cls.is_abstract_record())
cls = get_cursor(tu, 'Y')
self.assertFalse(cls.is_abstract_record())
def test_is_scoped_enum(self):
"""Ensure Cursor.is_scoped_enum works."""
source = 'class X {}; enum RegularEnum {}; enum class ScopedEnum {};'
tu = get_tu(source, lang='cpp')
cls = get_cursor(tu, 'X')
regular_enum = get_cursor(tu, 'RegularEnum')
scoped_enum = get_cursor(tu, 'ScopedEnum')
self.assertIsNotNone(cls)
self.assertIsNotNone(regular_enum)
self.assertIsNotNone(scoped_enum)
self.assertFalse(cls.is_scoped_enum())
self.assertFalse(regular_enum.is_scoped_enum())
self.assertTrue(scoped_enum.is_scoped_enum())
def test_underlying_type(self):
tu = get_tu('typedef int foo;')
typedef = get_cursor(tu, 'foo')
self.assertIsNotNone(typedef)
self.assertTrue(typedef.kind.is_declaration())
underlying = typedef.underlying_typedef_type
self.assertEqual(underlying.kind, TypeKind.INT)
def test_semantic_parent(self):
tu = get_tu(kParentTest, 'cpp')
curs = get_cursors(tu, 'f')
decl = get_cursor(tu, 'C')
self.assertEqual(len(curs), 2)
self.assertEqual(curs[0].semantic_parent, curs[1].semantic_parent)
self.assertEqual(curs[0].semantic_parent, decl)
def test_lexical_parent(self):
tu = get_tu(kParentTest, 'cpp')
curs = get_cursors(tu, 'f')
decl = get_cursor(tu, 'C')
self.assertEqual(len(curs), 2)
self.assertNotEqual(curs[0].lexical_parent, curs[1].lexical_parent)
self.assertEqual(curs[0].lexical_parent, decl)
self.assertEqual(curs[1].lexical_parent, tu.cursor)
def test_enum_type(self):
tu = get_tu('enum TEST { FOO=1, BAR=2 };')
enum = get_cursor(tu, 'TEST')
self.assertIsNotNone(enum)
self.assertEqual(enum.kind, CursorKind.ENUM_DECL)
enum_type = enum.enum_type
self.assertEqual(enum_type.kind, TypeKind.UINT)
def test_enum_type_cpp(self):
tu = get_tu('enum TEST : long long { FOO=1, BAR=2 };', lang="cpp")
enum = get_cursor(tu, 'TEST')
self.assertIsNotNone(enum)
self.assertEqual(enum.kind, CursorKind.ENUM_DECL)
self.assertEqual(enum.enum_type.kind, TypeKind.LONGLONG)
def test_objc_type_encoding(self):
tu = get_tu('int i;', lang='objc')
i = get_cursor(tu, 'i')
self.assertIsNotNone(i)
self.assertEqual(i.objc_type_encoding, 'i')
def test_enum_values(self):
tu = get_tu('enum TEST { SPAM=1, EGG, HAM = EGG * 20};')
enum = get_cursor(tu, 'TEST')
self.assertIsNotNone(enum)
self.assertEqual(enum.kind, CursorKind.ENUM_DECL)
enum_constants = list(enum.get_children())
self.assertEqual(len(enum_constants), 3)
spam, egg, ham = enum_constants
self.assertEqual(spam.kind, CursorKind.ENUM_CONSTANT_DECL)
self.assertEqual(spam.enum_value, 1)
self.assertEqual(egg.kind, CursorKind.ENUM_CONSTANT_DECL)
self.assertEqual(egg.enum_value, 2)
self.assertEqual(ham.kind, CursorKind.ENUM_CONSTANT_DECL)
self.assertEqual(ham.enum_value, 40)
def test_enum_values_cpp(self):
tu = get_tu('enum TEST : long long { SPAM = -1, HAM = 0x10000000000};', lang="cpp")
enum = get_cursor(tu, 'TEST')
self.assertIsNotNone(enum)
self.assertEqual(enum.kind, CursorKind.ENUM_DECL)
enum_constants = list(enum.get_children())
self.assertEqual(len(enum_constants), 2)
spam, ham = enum_constants
self.assertEqual(spam.kind, CursorKind.ENUM_CONSTANT_DECL)
self.assertEqual(spam.enum_value, -1)
self.assertEqual(ham.kind, CursorKind.ENUM_CONSTANT_DECL)
self.assertEqual(ham.enum_value, 0x10000000000)
def test_annotation_attribute(self):
tu = get_tu('int foo (void) __attribute__ ((annotate("here be annotation attribute")));')
foo = get_cursor(tu, 'foo')
self.assertIsNotNone(foo)
for c in foo.get_children():
if c.kind == CursorKind.ANNOTATE_ATTR:
self.assertEqual(c.displayname, "here be annotation attribute")
break
else:
self.fail("Couldn't find annotation")
def test_annotation_template(self):
annotation = '__attribute__ ((annotate("annotation")))'
for source, kind in [
('int foo (T value) %s;', CursorKind.FUNCTION_TEMPLATE),
('class %s foo {};', CursorKind.CLASS_TEMPLATE),
]:
source = 'template<typename T> ' + (source % annotation)
tu = get_tu(source, lang="cpp")
foo = get_cursor(tu, 'foo')
self.assertIsNotNone(foo)
self.assertEqual(foo.kind, kind)
for c in foo.get_children():
if c.kind == CursorKind.ANNOTATE_ATTR:
self.assertEqual(c.displayname, "annotation")
break
else:
self.fail("Couldn't find annotation for {}".format(kind))
def test_result_type(self):
tu = get_tu('int foo();')
foo = get_cursor(tu, 'foo')
self.assertIsNotNone(foo)
t = foo.result_type
self.assertEqual(t.kind, TypeKind.INT)
def test_availability(self):
tu = get_tu('class A { A(A const&) = delete; };', lang='cpp')
# AvailabilityKind.AVAILABLE
cursor = get_cursor(tu, 'A')
self.assertEqual(cursor.kind, CursorKind.CLASS_DECL)
self.assertEqual(cursor.availability, AvailabilityKind.AVAILABLE)
# AvailabilityKind.NOT_AVAILABLE
cursors = get_cursors(tu, 'A')
for c in cursors:
if c.kind == CursorKind.CONSTRUCTOR:
self.assertEqual(c.availability, AvailabilityKind.NOT_AVAILABLE)
break
else:
self.fail("Could not find cursor for deleted constructor")
# AvailabilityKind.DEPRECATED
tu = get_tu('void test() __attribute__((deprecated));', lang='cpp')
cursor = get_cursor(tu, 'test')
self.assertEqual(cursor.availability, AvailabilityKind.DEPRECATED)
# AvailabilityKind.NOT_ACCESSIBLE is only used in the code completion results
def test_get_tokens(self):
"""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())
self.assertEqual(len(tokens), 6)
self.assertEqual(tokens[0].spelling, 'int')
self.assertEqual(tokens[1].spelling, 'foo')
def test_get_token_cursor(self):
"""Ensure we can map tokens to cursors."""
tu = get_tu('class A {}; int foo(A var = A());', lang='cpp')
foo = get_cursor(tu, 'foo')
for cursor in foo.walk_preorder():
if cursor.kind.is_expression() and not cursor.kind.is_statement():
break
else:
self.fail("Could not find default value expression")
tokens = list(cursor.get_tokens())
self.assertEqual(len(tokens), 4, [t.spelling for t in tokens])
self.assertEqual(tokens[0].spelling, '=')
self.assertEqual(tokens[1].spelling, 'A')
self.assertEqual(tokens[2].spelling, '(')
self.assertEqual(tokens[3].spelling, ')')
t_cursor = tokens[1].cursor
self.assertEqual(t_cursor.kind, CursorKind.TYPE_REF)
r_cursor = t_cursor.referenced # should not raise an exception
self.assertEqual(r_cursor.kind, CursorKind.CLASS_DECL)
def test_get_arguments(self):
tu = get_tu('void foo(int i, int j);')
foo = get_cursor(tu, 'foo')
arguments = list(foo.get_arguments())
self.assertEqual(len(arguments), 2)
self.assertEqual(arguments[0].spelling, "i")
self.assertEqual(arguments[1].spelling, "j")
def test_get_num_template_arguments(self):
tu = get_tu(kTemplateArgTest, lang='cpp')
foos = get_cursors(tu, 'foo')
self.assertEqual(foos[1].get_num_template_arguments(), 3)
def test_get_template_argument_kind(self):
tu = get_tu(kTemplateArgTest, lang='cpp')
foos = get_cursors(tu, 'foo')
self.assertEqual(foos[1].get_template_argument_kind(0), TemplateArgumentKind.INTEGRAL)
self.assertEqual(foos[1].get_template_argument_kind(1), TemplateArgumentKind.TYPE)
self.assertEqual(foos[1].get_template_argument_kind(2), TemplateArgumentKind.INTEGRAL)
def test_get_template_argument_type(self):
tu = get_tu(kTemplateArgTest, lang='cpp')
foos = get_cursors(tu, 'foo')
self.assertEqual(foos[1].get_template_argument_type(1).kind, TypeKind.FLOAT)
def test_get_template_argument_value(self):
tu = get_tu(kTemplateArgTest, lang='cpp')
foos = get_cursors(tu, 'foo')
self.assertEqual(foos[1].get_template_argument_value(0), -7)
self.assertEqual(foos[1].get_template_argument_value(2), True)
def test_get_template_argument_unsigned_value(self):
tu = get_tu(kTemplateArgTest, lang='cpp')
foos = get_cursors(tu, 'foo')
self.assertEqual(foos[1].get_template_argument_unsigned_value(0), 2 ** 32 - 7)
self.assertEqual(foos[1].get_template_argument_unsigned_value(2), True)
def test_referenced(self):
tu = get_tu('void foo(); void bar() { foo(); }')
foo = get_cursor(tu, 'foo')
bar = get_cursor(tu, 'bar')
for c in bar.get_children():
if c.kind == CursorKind.CALL_EXPR:
self.assertEqual(c.referenced.spelling, foo.spelling)
break
def test_mangled_name(self):
kInputForMangling = """\
int foo(int, int);
"""
tu = get_tu(kInputForMangling, lang='cpp')
foo = get_cursor(tu, 'foo')
# Since libclang does not link in targets, we cannot pass a triple to it
# and force the target. To enable this test to pass on all platforms, accept
# all valid manglings.
# [c-index-test handles this by running the source through clang, emitting
# an AST file and running libclang on that AST file]
self.assertIn(foo.mangled_name, ('_Z3fooii', '__Z3fooii', '?foo@@YAHHH'))

View File

@ -1,49 +1,53 @@
from clang.cindex import CursorKind
def test_name():
assert CursorKind.UNEXPOSED_DECL.name is 'UNEXPOSED_DECL'
import unittest
def test_get_all_kinds():
kinds = CursorKind.get_all_kinds()
assert CursorKind.UNEXPOSED_DECL in kinds
assert CursorKind.TRANSLATION_UNIT in kinds
assert CursorKind.VARIABLE_REF in kinds
assert CursorKind.LAMBDA_EXPR in kinds
assert CursorKind.OBJ_BOOL_LITERAL_EXPR in kinds
assert CursorKind.OBJ_SELF_EXPR in kinds
assert CursorKind.MS_ASM_STMT in kinds
assert CursorKind.MODULE_IMPORT_DECL in kinds
assert CursorKind.TYPE_ALIAS_TEMPLATE_DECL in kinds
def test_kind_groups():
"""Check that every kind classifies to exactly one group."""
class TestCursorKind(unittest.TestCase):
def test_name(self):
self.assertTrue(CursorKind.UNEXPOSED_DECL.name is 'UNEXPOSED_DECL')
assert CursorKind.UNEXPOSED_DECL.is_declaration()
assert CursorKind.TYPE_REF.is_reference()
assert CursorKind.DECL_REF_EXPR.is_expression()
assert CursorKind.UNEXPOSED_STMT.is_statement()
assert CursorKind.INVALID_FILE.is_invalid()
def test_get_all_kinds(self):
kinds = CursorKind.get_all_kinds()
self.assertIn(CursorKind.UNEXPOSED_DECL, kinds)
self.assertIn(CursorKind.TRANSLATION_UNIT, kinds)
self.assertIn(CursorKind.VARIABLE_REF, kinds)
self.assertIn(CursorKind.LAMBDA_EXPR, kinds)
self.assertIn(CursorKind.OBJ_BOOL_LITERAL_EXPR, kinds)
self.assertIn(CursorKind.OBJ_SELF_EXPR, kinds)
self.assertIn(CursorKind.MS_ASM_STMT, kinds)
self.assertIn(CursorKind.MODULE_IMPORT_DECL, kinds)
self.assertIn(CursorKind.TYPE_ALIAS_TEMPLATE_DECL, kinds)
assert CursorKind.TRANSLATION_UNIT.is_translation_unit()
assert not CursorKind.TYPE_REF.is_translation_unit()
def test_kind_groups(self):
"""Check that every kind classifies to exactly one group."""
assert CursorKind.PREPROCESSING_DIRECTIVE.is_preprocessing()
assert not CursorKind.TYPE_REF.is_preprocessing()
self.assertTrue(CursorKind.UNEXPOSED_DECL.is_declaration())
self.assertTrue(CursorKind.TYPE_REF.is_reference())
self.assertTrue(CursorKind.DECL_REF_EXPR.is_expression())
self.assertTrue(CursorKind.UNEXPOSED_STMT.is_statement())
self.assertTrue(CursorKind.INVALID_FILE.is_invalid())
assert CursorKind.UNEXPOSED_DECL.is_unexposed()
assert not CursorKind.TYPE_REF.is_unexposed()
self.assertTrue(CursorKind.TRANSLATION_UNIT.is_translation_unit())
self.assertFalse(CursorKind.TYPE_REF.is_translation_unit())
for k in CursorKind.get_all_kinds():
group = [n for n in ('is_declaration', 'is_reference', 'is_expression',
'is_statement', 'is_invalid', 'is_attribute')
if getattr(k, n)()]
self.assertTrue(CursorKind.PREPROCESSING_DIRECTIVE.is_preprocessing())
self.assertFalse(CursorKind.TYPE_REF.is_preprocessing())
if k in ( CursorKind.TRANSLATION_UNIT,
CursorKind.MACRO_DEFINITION,
CursorKind.MACRO_INSTANTIATION,
CursorKind.INCLUSION_DIRECTIVE,
CursorKind.PREPROCESSING_DIRECTIVE,
CursorKind.OVERLOAD_CANDIDATE):
assert len(group) == 0
else:
assert len(group) == 1
self.assertTrue(CursorKind.UNEXPOSED_DECL.is_unexposed())
self.assertFalse(CursorKind.TYPE_REF.is_unexposed())
for k in CursorKind.get_all_kinds():
group = [n for n in ('is_declaration', 'is_reference', 'is_expression',
'is_statement', 'is_invalid', 'is_attribute')
if getattr(k, n)()]
if k in ( CursorKind.TRANSLATION_UNIT,
CursorKind.MACRO_DEFINITION,
CursorKind.MACRO_INSTANTIATION,
CursorKind.INCLUSION_DIRECTIVE,
CursorKind.PREPROCESSING_DIRECTIVE,
CursorKind.OVERLOAD_CANDIDATE):
self.assertEqual(len(group), 0)
else:
self.assertEqual(len(group), 1)

View File

@ -1,102 +1,105 @@
from clang.cindex import *
from .util import get_tu
import unittest
# FIXME: We need support for invalid translation units to test better.
def test_diagnostic_warning():
tu = get_tu('int f0() {}\n')
assert len(tu.diagnostics) == 1
assert tu.diagnostics[0].severity == Diagnostic.Warning
assert tu.diagnostics[0].location.line == 1
assert tu.diagnostics[0].location.column == 11
assert (tu.diagnostics[0].spelling ==
'control reaches end of non-void function')
def test_diagnostic_note():
# FIXME: We aren't getting notes here for some reason.
tu = get_tu('#define A x\nvoid *A = 1;\n')
assert len(tu.diagnostics) == 1
assert tu.diagnostics[0].severity == Diagnostic.Warning
assert tu.diagnostics[0].location.line == 2
assert tu.diagnostics[0].location.column == 7
assert 'incompatible' in tu.diagnostics[0].spelling
# assert tu.diagnostics[1].severity == Diagnostic.Note
# assert tu.diagnostics[1].location.line == 1
# assert tu.diagnostics[1].location.column == 11
# assert tu.diagnostics[1].spelling == 'instantiated from'
class TestDiagnostics(unittest.TestCase):
def test_diagnostic_warning(self):
tu = get_tu('int f0() {}\n')
self.assertEqual(len(tu.diagnostics), 1)
self.assertEqual(tu.diagnostics[0].severity, Diagnostic.Warning)
self.assertEqual(tu.diagnostics[0].location.line, 1)
self.assertEqual(tu.diagnostics[0].location.column, 11)
self.assertEqual(tu.diagnostics[0].spelling,
'control reaches end of non-void function')
def test_diagnostic_fixit():
tu = get_tu('struct { int f0; } x = { f0 : 1 };')
assert len(tu.diagnostics) == 1
assert tu.diagnostics[0].severity == Diagnostic.Warning
assert tu.diagnostics[0].location.line == 1
assert tu.diagnostics[0].location.column == 26
assert tu.diagnostics[0].spelling.startswith('use of GNU old-style')
assert len(tu.diagnostics[0].fixits) == 1
assert tu.diagnostics[0].fixits[0].range.start.line == 1
assert tu.diagnostics[0].fixits[0].range.start.column == 26
assert tu.diagnostics[0].fixits[0].range.end.line == 1
assert tu.diagnostics[0].fixits[0].range.end.column == 30
assert tu.diagnostics[0].fixits[0].value == '.f0 = '
def test_diagnostic_note(self):
# FIXME: We aren't getting notes here for some reason.
tu = get_tu('#define A x\nvoid *A = 1;\n')
self.assertEqual(len(tu.diagnostics), 1)
self.assertEqual(tu.diagnostics[0].severity, Diagnostic.Warning)
self.assertEqual(tu.diagnostics[0].location.line, 2)
self.assertEqual(tu.diagnostics[0].location.column, 7)
self.assertIn('incompatible', tu.diagnostics[0].spelling)
# self.assertEqual(tu.diagnostics[1].severity, Diagnostic.Note)
# self.assertEqual(tu.diagnostics[1].location.line, 1)
# self.assertEqual(tu.diagnostics[1].location.column, 11)
# self.assertEqual(tu.diagnostics[1].spelling, 'instantiated from')
def test_diagnostic_range():
tu = get_tu('void f() { int i = "a" + 1; }')
assert len(tu.diagnostics) == 1
assert tu.diagnostics[0].severity == Diagnostic.Warning
assert tu.diagnostics[0].location.line == 1
assert tu.diagnostics[0].location.column == 16
assert tu.diagnostics[0].spelling.startswith('incompatible pointer to')
assert len(tu.diagnostics[0].fixits) == 0
assert len(tu.diagnostics[0].ranges) == 1
assert tu.diagnostics[0].ranges[0].start.line == 1
assert tu.diagnostics[0].ranges[0].start.column == 20
assert tu.diagnostics[0].ranges[0].end.line == 1
assert tu.diagnostics[0].ranges[0].end.column == 27
try:
tu.diagnostics[0].ranges[1].start.line
except IndexError:
assert True
else:
assert False
def test_diagnostic_fixit(self):
tu = get_tu('struct { int f0; } x = { f0 : 1 };')
self.assertEqual(len(tu.diagnostics), 1)
self.assertEqual(tu.diagnostics[0].severity, Diagnostic.Warning)
self.assertEqual(tu.diagnostics[0].location.line, 1)
self.assertEqual(tu.diagnostics[0].location.column, 26)
self.assertRegexpMatches(tu.diagnostics[0].spelling,
'use of GNU old-style.*')
self.assertEqual(len(tu.diagnostics[0].fixits), 1)
self.assertEqual(tu.diagnostics[0].fixits[0].range.start.line, 1)
self.assertEqual(tu.diagnostics[0].fixits[0].range.start.column, 26)
self.assertEqual(tu.diagnostics[0].fixits[0].range.end.line, 1)
self.assertEqual(tu.diagnostics[0].fixits[0].range.end.column, 30)
self.assertEqual(tu.diagnostics[0].fixits[0].value, '.f0 = ')
def test_diagnostic_category():
"""Ensure that category properties work."""
tu = get_tu('int f(int i) { return 7; }', all_warnings=True)
assert len(tu.diagnostics) == 1
d = tu.diagnostics[0]
def test_diagnostic_range(self):
tu = get_tu('void f() { int i = "a" + 1; }')
self.assertEqual(len(tu.diagnostics), 1)
self.assertEqual(tu.diagnostics[0].severity, Diagnostic.Warning)
self.assertEqual(tu.diagnostics[0].location.line, 1)
self.assertEqual(tu.diagnostics[0].location.column, 16)
self.assertRegexpMatches(tu.diagnostics[0].spelling,
'incompatible pointer to.*')
self.assertEqual(len(tu.diagnostics[0].fixits), 0)
self.assertEqual(len(tu.diagnostics[0].ranges), 1)
self.assertEqual(tu.diagnostics[0].ranges[0].start.line, 1)
self.assertEqual(tu.diagnostics[0].ranges[0].start.column, 20)
self.assertEqual(tu.diagnostics[0].ranges[0].end.line, 1)
self.assertEqual(tu.diagnostics[0].ranges[0].end.column, 27)
with self.assertRaises(IndexError):
tu.diagnostics[0].ranges[1].start.line
assert d.severity == Diagnostic.Warning
assert d.location.line == 1
assert d.location.column == 11
def test_diagnostic_category(self):
"""Ensure that category properties work."""
tu = get_tu('int f(int i) { return 7; }', all_warnings=True)
self.assertEqual(len(tu.diagnostics), 1)
d = tu.diagnostics[0]
assert d.category_number == 2
assert d.category_name == 'Semantic Issue'
self.assertEqual(d.severity, Diagnostic.Warning)
self.assertEqual(d.location.line, 1)
self.assertEqual(d.location.column, 11)
def test_diagnostic_option():
"""Ensure that category option properties work."""
tu = get_tu('int f(int i) { return 7; }', all_warnings=True)
assert len(tu.diagnostics) == 1
d = tu.diagnostics[0]
self.assertEqual(d.category_number, 2)
self.assertEqual(d.category_name, 'Semantic Issue')
assert d.option == '-Wunused-parameter'
assert d.disable_option == '-Wno-unused-parameter'
def test_diagnostic_option(self):
"""Ensure that category option properties work."""
tu = get_tu('int f(int i) { return 7; }', all_warnings=True)
self.assertEqual(len(tu.diagnostics), 1)
d = tu.diagnostics[0]
def test_diagnostic_children():
tu = get_tu('void f(int x) {} void g() { f(); }')
assert len(tu.diagnostics) == 1
d = tu.diagnostics[0]
self.assertEqual(d.option, '-Wunused-parameter')
self.assertEqual(d.disable_option, '-Wno-unused-parameter')
children = d.children
assert len(children) == 1
assert children[0].severity == Diagnostic.Note
assert children[0].spelling.endswith('declared here')
assert children[0].location.line == 1
assert children[0].location.column == 1
def test_diagnostic_children(self):
tu = get_tu('void f(int x) {} void g() { f(); }')
self.assertEqual(len(tu.diagnostics), 1)
d = tu.diagnostics[0]
def test_diagnostic_string_repr():
tu = get_tu('struct MissingSemicolon{}')
assert len(tu.diagnostics) == 1
d = tu.diagnostics[0]
children = d.children
self.assertEqual(len(children), 1)
self.assertEqual(children[0].severity, Diagnostic.Note)
self.assertRegexpMatches(children[0].spelling,
'.*declared here')
self.assertEqual(children[0].location.line, 1)
self.assertEqual(children[0].location.column, 1)
assert repr(d) == '<Diagnostic severity 3, location <SourceLocation file \'t.c\', line 1, column 26>, spelling "expected \';\' after struct">'
def test_diagnostic_string_repr(self):
tu = get_tu('struct MissingSemicolon{}')
self.assertEqual(len(tu.diagnostics), 1)
d = tu.diagnostics[0]
self.assertEqual(repr(d), '<Diagnostic severity 3, location <SourceLocation file \'t.c\', line 1, column 26>, spelling "expected \';\' after struct">')

View File

@ -2,6 +2,8 @@
from clang.cindex import ExceptionSpecificationKind
from .util import get_tu
import unittest
def find_function_declarations(node, declarations=[]):
if node.kind == clang.cindex.CursorKind.FUNCTION_DECL:
@ -11,17 +13,18 @@ def find_function_declarations(node, declarations=[]):
return declarations
def test_exception_specification_kind():
source = """int square1(int x);
int square2(int x) noexcept;
int square3(int x) noexcept(noexcept(x * x));"""
class TestExceptionSpecificationKind(unittest.TestCase):
def test_exception_specification_kind(self):
source = """int square1(int x);
int square2(int x) noexcept;
int square3(int x) noexcept(noexcept(x * x));"""
tu = get_tu(source, lang='cpp', flags=['-std=c++14'])
tu = get_tu(source, lang='cpp', flags=['-std=c++14'])
declarations = find_function_declarations(tu.cursor)
expected = [
('square1', ExceptionSpecificationKind.NONE),
('square2', ExceptionSpecificationKind.BASIC_NOEXCEPT),
('square3', ExceptionSpecificationKind.COMPUTED_NOEXCEPT)
]
assert declarations == expected
declarations = find_function_declarations(tu.cursor)
expected = [
('square1', ExceptionSpecificationKind.NONE),
('square2', ExceptionSpecificationKind.BASIC_NOEXCEPT),
('square3', ExceptionSpecificationKind.COMPUTED_NOEXCEPT)
]
self.assertListEqual(declarations, expected)

View File

@ -1,9 +1,13 @@
from clang.cindex import Index, File
def test_file():
index = Index.create()
tu = index.parse('t.c', unsaved_files = [('t.c', "")])
file = File.from_name(tu, "t.c")
assert str(file) == "t.c"
assert file.name == "t.c"
assert repr(file) == "<File: t.c>"
import unittest
class TestFile(unittest.TestCase):
def test_file(self):
index = Index.create()
tu = index.parse('t.c', unsaved_files = [('t.c', "")])
file = File.from_name(tu, "t.c")
self.assertEqual(str(file), "t.c")
self.assertEqual(file.name, "t.c")
self.assertEqual(repr(file), "<File: t.c>")

View File

@ -1,15 +1,21 @@
from clang.cindex import *
import os
import unittest
kInputsDir = os.path.join(os.path.dirname(__file__), 'INPUTS')
def test_create():
index = Index.create()
# FIXME: test Index.read
class TestIndex(unittest.TestCase):
def test_create(self):
index = Index.create()
def test_parse():
index = Index.create()
assert isinstance(index, Index)
tu = index.parse(os.path.join(kInputsDir, 'hello.cpp'))
assert isinstance(tu, TranslationUnit)
# FIXME: test Index.read
def test_parse(self):
index = Index.create()
self.assertIsInstance(index, Index)
tu = index.parse(os.path.join(kInputsDir, 'hello.cpp'))
self.assertIsInstance(tu, TranslationUnit)
tu = index.parse(None, ['-c', os.path.join(kInputsDir, 'hello.cpp')])
self.assertIsInstance(tu, TranslationUnit)

View File

@ -0,0 +1,33 @@
from clang.cindex import LinkageKind
from clang.cindex import Cursor
from clang.cindex import TranslationUnit
from .util import get_cursor
from .util import get_tu
import unittest
class TestLinkage(unittest.TestCase):
def test_linkage(self):
"""Ensure that linkage specifers are available on cursors"""
tu = get_tu("""
void foo() { int no_linkage; }
static int internal;
namespace { struct unique_external_type {} }
unique_external_type unique_external;
extern int external;
""", lang = 'cpp')
no_linkage = get_cursor(tu.cursor, 'no_linkage')
self.assertEqual(no_linkage.linkage, LinkageKind.NO_LINKAGE)
internal = get_cursor(tu.cursor, 'internal')
self.assertEqual(internal.linkage, LinkageKind.INTERNAL)
unique_external = get_cursor(tu.cursor, 'unique_external')
self.assertEqual(unique_external.linkage, LinkageKind.UNIQUE_EXTERNAL)
external = get_cursor(tu.cursor, 'external')
self.assertEqual(external.linkage, LinkageKind.EXTERNAL)

View File

@ -5,91 +5,96 @@
from .util import get_cursor
from .util import get_tu
import unittest
baseInput="int one;\nint two;\n"
def assert_location(loc, line, column, offset):
assert loc.line == line
assert loc.column == column
assert loc.offset == offset
def test_location():
tu = get_tu(baseInput)
one = get_cursor(tu, 'one')
two = get_cursor(tu, 'two')
class TestLocation(unittest.TestCase):
def assert_location(self, loc, line, column, offset):
self.assertEqual(loc.line, line)
self.assertEqual(loc.column, column)
self.assertEqual(loc.offset, offset)
assert one is not None
assert two is not None
def test_location(self):
tu = get_tu(baseInput)
one = get_cursor(tu, 'one')
two = get_cursor(tu, 'two')
assert_location(one.location,line=1,column=5,offset=4)
assert_location(two.location,line=2,column=5,offset=13)
self.assertIsNotNone(one)
self.assertIsNotNone(two)
# adding a linebreak at top should keep columns same
tu = get_tu('\n' + baseInput)
one = get_cursor(tu, 'one')
two = get_cursor(tu, 'two')
self.assert_location(one.location,line=1,column=5,offset=4)
self.assert_location(two.location,line=2,column=5,offset=13)
assert one is not None
assert two is not None
# adding a linebreak at top should keep columns same
tu = get_tu('\n' + baseInput)
one = get_cursor(tu, 'one')
two = get_cursor(tu, 'two')
assert_location(one.location,line=2,column=5,offset=5)
assert_location(two.location,line=3,column=5,offset=14)
self.assertIsNotNone(one)
self.assertIsNotNone(two)
# adding a space should affect column on first line only
tu = get_tu(' ' + baseInput)
one = get_cursor(tu, 'one')
two = get_cursor(tu, 'two')
self.assert_location(one.location,line=2,column=5,offset=5)
self.assert_location(two.location,line=3,column=5,offset=14)
assert_location(one.location,line=1,column=6,offset=5)
assert_location(two.location,line=2,column=5,offset=14)
# adding a space should affect column on first line only
tu = get_tu(' ' + baseInput)
one = get_cursor(tu, 'one')
two = get_cursor(tu, 'two')
# define the expected location ourselves and see if it matches
# the returned location
tu = get_tu(baseInput)
self.assert_location(one.location,line=1,column=6,offset=5)
self.assert_location(two.location,line=2,column=5,offset=14)
file = File.from_name(tu, 't.c')
location = SourceLocation.from_position(tu, file, 1, 5)
cursor = Cursor.from_location(tu, location)
# define the expected location ourselves and see if it matches
# the returned location
tu = get_tu(baseInput)
one = get_cursor(tu, 'one')
assert one is not None
assert one == cursor
file = File.from_name(tu, 't.c')
location = SourceLocation.from_position(tu, file, 1, 5)
cursor = Cursor.from_location(tu, location)
# Ensure locations referring to the same entity are equivalent.
location2 = SourceLocation.from_position(tu, file, 1, 5)
assert location == location2
location3 = SourceLocation.from_position(tu, file, 1, 4)
assert location2 != location3
one = get_cursor(tu, 'one')
self.assertIsNotNone(one)
self.assertEqual(one, cursor)
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
# Ensure locations referring to the same entity are equivalent.
location2 = SourceLocation.from_position(tu, file, 1, 5)
self.assertEqual(location, location2)
location3 = SourceLocation.from_position(tu, file, 1, 4)
self.assertNotEqual(location2, location3)
assert verified
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']:
self.assertEqual(n, cursor)
verified = True
def test_extent():
tu = get_tu(baseInput)
one = get_cursor(tu, 'one')
two = get_cursor(tu, 'two')
self.assertTrue(verified)
assert_location(one.extent.start,line=1,column=1,offset=0)
assert_location(one.extent.end,line=1,column=8,offset=7)
assert baseInput[one.extent.start.offset:one.extent.end.offset] == "int one"
def test_extent(self):
tu = get_tu(baseInput)
one = get_cursor(tu, 'one')
two = get_cursor(tu, 'two')
assert_location(two.extent.start,line=2,column=1,offset=9)
assert_location(two.extent.end,line=2,column=8,offset=16)
assert baseInput[two.extent.start.offset:two.extent.end.offset] == "int two"
self.assert_location(one.extent.start,line=1,column=1,offset=0)
self.assert_location(one.extent.end,line=1,column=8,offset=7)
self.assertEqual(baseInput[one.extent.start.offset:one.extent.end.offset], "int one")
file = File.from_name(tu, 't.c')
location1 = SourceLocation.from_position(tu, file, 1, 1)
location2 = SourceLocation.from_position(tu, file, 1, 8)
self.assert_location(two.extent.start,line=2,column=1,offset=9)
self.assert_location(two.extent.end,line=2,column=8,offset=16)
self.assertEqual(baseInput[two.extent.start.offset:two.extent.end.offset], "int two")
range1 = SourceRange.from_locations(location1, location2)
range2 = SourceRange.from_locations(location1, location2)
assert range1 == range2
file = File.from_name(tu, 't.c')
location1 = SourceLocation.from_position(tu, file, 1, 1)
location2 = SourceLocation.from_position(tu, file, 1, 8)
location3 = SourceLocation.from_position(tu, file, 1, 6)
range3 = SourceRange.from_locations(location1, location3)
assert range1 != range3
range1 = SourceRange.from_locations(location1, location2)
range2 = SourceRange.from_locations(location1, location2)
self.assertEqual(range1, range2)
location3 = SourceLocation.from_position(tu, file, 1, 6)
range3 = SourceRange.from_locations(location1, location3)
self.assertNotEqual(range1, range3)

View File

@ -0,0 +1,49 @@
from clang.cindex import TLSKind
from clang.cindex import Cursor
from clang.cindex import TranslationUnit
from .util import get_cursor
from .util import get_tu
import unittest
class TestTLSKind(unittest.TestCase):
def test_tls_kind(self):
"""Ensure that thread-local storage kinds are available on cursors."""
tu = get_tu("""
int tls_none;
thread_local int tls_dynamic;
_Thread_local int tls_static;
""", lang = 'cpp')
tls_none = get_cursor(tu.cursor, 'tls_none')
self.assertEqual(tls_none.tls_kind, TLSKind.NONE)
tls_dynamic = get_cursor(tu.cursor, 'tls_dynamic')
self.assertEqual(tls_dynamic.tls_kind, TLSKind.DYNAMIC)
tls_static = get_cursor(tu.cursor, 'tls_static')
self.assertEqual(tls_static.tls_kind, TLSKind.STATIC)
# The following case tests '__declspec(thread)'. Since it is a Microsoft
# specific extension, specific flags are required for the parser to pick
# these up.
flags = ['-fms-extensions', '-target', 'x86_64-unknown-windows-win32',
'-fms-compatibility-version=18']
tu = get_tu("""
__declspec(thread) int tls_declspec_msvc18;
""", lang = 'cpp', flags=flags)
tls_declspec_msvc18 = get_cursor(tu.cursor, 'tls_declspec_msvc18')
self.assertEqual(tls_declspec_msvc18.tls_kind, TLSKind.STATIC)
flags = ['-fms-extensions', '-target', 'x86_64-unknown-windows-win32',
'-fms-compatibility-version=19']
tu = get_tu("""
__declspec(thread) int tls_declspec_msvc19;
""", lang = 'cpp', flags=flags)
tls_declspec_msvc19 = get_cursor(tu.cursor, 'tls_declspec_msvc19')
self.assertEqual(tls_declspec_msvc19.tls_kind, TLSKind.DYNAMIC)

View File

@ -1,43 +1,44 @@
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."""
import unittest
t = TokenKind(5, 'foo')
eq_(t.value, 5)
eq_(t.name, 'foo')
class TestTokenKind(unittest.TestCase):
def test_constructor(self):
"""Ensure TokenKind constructor works as expected."""
@raises(ValueError)
def test_bad_register():
"""Ensure a duplicate value is rejected for registration."""
t = TokenKind(5, 'foo')
TokenKind.register(2, 'foo')
self.assertEqual(t.value, 5)
self.assertEqual(t.name, 'foo')
@raises(ValueError)
def test_unknown_value():
"""Ensure trying to fetch an unknown value raises."""
def test_bad_register(self):
"""Ensure a duplicate value is rejected for registration."""
TokenKind.from_value(-1)
with self.assertRaises(ValueError):
TokenKind.register(2, 'foo')
def test_registration():
"""Ensure that items registered appear as class attributes."""
ok_(hasattr(TokenKind, 'LITERAL'))
literal = TokenKind.LITERAL
def test_unknown_value(self):
"""Ensure trying to fetch an unknown value raises."""
ok_(isinstance(literal, TokenKind))
with self.assertRaises(ValueError):
TokenKind.from_value(-1)
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_registration(self):
"""Ensure that items registered appear as class attributes."""
self.assertTrue(hasattr(TokenKind, 'LITERAL'))
literal = TokenKind.LITERAL
def test_repr():
"""Ensure repr() works."""
self.assertIsInstance(literal, TokenKind)
r = repr(TokenKind.LITERAL)
eq_(r, 'TokenKind.LITERAL')
def test_from_value(self):
"""Ensure registered values can be obtained from from_value()."""
t = TokenKind.from_value(3)
self.assertIsInstance(t, TokenKind)
self.assertEqual(t, TokenKind.LITERAL)
def test_repr(self):
"""Ensure repr() works."""
r = repr(TokenKind.LITERAL)
self.assertEqual(r, 'TokenKind.LITERAL')

View File

@ -3,50 +3,52 @@
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))
import unittest
assert len(tokens) == 4
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
class TestTokens(unittest.TestCase):
def test_token_to_cursor(self):
"""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))
def test_token_location():
"""Ensure Token.location works."""
self.assertEqual(len(tokens), 4)
self.assertEqual(tokens[1].spelling, 'i')
self.assertEqual(tokens[1].kind, TokenKind.IDENTIFIER)
tu = get_tu('int foo = 10;')
r = tu.get_extent('t.c', (0, 11))
cursor = tokens[1].cursor
self.assertEqual(cursor.kind, CursorKind.VAR_DECL)
self.assertEqual(tokens[1].cursor, tokens[2].cursor)
tokens = list(tu.get_tokens(extent=r))
eq_(len(tokens), 4)
def test_token_location(self):
"""Ensure Token.location works."""
loc = tokens[1].location
ok_(isinstance(loc, SourceLocation))
eq_(loc.line, 1)
eq_(loc.column, 5)
eq_(loc.offset, 4)
tu = get_tu('int foo = 10;')
r = tu.get_extent('t.c', (0, 11))
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))
self.assertEqual(len(tokens), 4)
tokens = list(tu.get_tokens(extent=r))
eq_(len(tokens), 4)
loc = tokens[1].location
self.assertIsInstance(loc, SourceLocation)
self.assertEqual(loc.line, 1)
self.assertEqual(loc.column, 5)
self.assertEqual(loc.offset, 4)
extent = tokens[1].extent
ok_(isinstance(extent, SourceRange))
def test_token_extent(self):
"""Ensure Token.extent works."""
tu = get_tu('int foo = 10;')
r = tu.get_extent('t.c', (0, 11))
eq_(extent.start.offset, 4)
eq_(extent.end.offset, 7)
tokens = list(tu.get_tokens(extent=r))
self.assertEqual(len(tokens), 4)
extent = tokens[1].extent
self.assertIsInstance(extent, SourceRange)
self.assertEqual(extent.start.offset, 4)
self.assertEqual(extent.end.offset, 7)

View File

@ -1,6 +1,7 @@
import gc
import os
import tempfile
import unittest
from clang.cindex import CursorKind
from clang.cindex import Cursor
@ -14,83 +15,9 @@
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')
tu = TranslationUnit.from_source(path)
assert tu.spelling == path
def test_cursor():
path = os.path.join(kInputsDir, 'hello.cpp')
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')
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')
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():
tu = TranslationUnit.from_source('fake.c', ['-I./'], unsaved_files = [
('fake.c', """
#include "fake.h"
int x;
int SOME_DEFINE;
"""),
('./fake.h', """
#define SOME_DEFINE y
""")
])
spellings = [c.spelling for c in tu.cursor.get_children()]
assert spellings[-2] == 'x'
assert spellings[-1] == 'y'
def test_unsaved_files_2():
try:
from StringIO import StringIO
except:
from io import StringIO
tu = TranslationUnit.from_source('fake.c', unsaved_files = [
('fake.c', StringIO('int x;'))])
spellings = [c.spelling for c in tu.cursor.get_children()]
assert spellings[-1] == 'x'
def normpaths_equal(path1, path2):
""" Compares two paths for equality after normalizing them with
os.path.normpath
"""
return os.path.normpath(path1) == os.path.normpath(path2)
def test_includes():
def eq(expected, actual):
if not actual.is_input_file:
return normpaths_equal(expected[0], actual.source.name) and \
normpaths_equal(expected[1], actual.include.name)
else:
return normpaths_equal(expected[1], actual.include.name)
src = os.path.join(kInputsDir, 'include.cpp')
h1 = os.path.join(kInputsDir, "header1.h")
h2 = os.path.join(kInputsDir, "header2.h")
h3 = os.path.join(kInputsDir, "header3.h")
inc = [(src, h1), (h1, h3), (src, h2), (h2, h3)]
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.
@ -102,153 +29,227 @@ def save_tu(tu):
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.
def test_fail_from_source():
path = os.path.join(kInputsDir, 'non-existent.cpp')
try:
class TestTranslationUnit(unittest.TestCase):
def test_spelling(self):
path = os.path.join(kInputsDir, 'hello.cpp')
tu = TranslationUnit.from_source(path)
except TranslationUnitLoadError:
tu = None
assert tu == None
self.assertEqual(tu.spelling, path)
def test_fail_from_ast_file():
path = os.path.join(kInputsDir, 'non-existent.ast')
try:
tu = TranslationUnit.from_ast_file(path)
except TranslationUnitLoadError:
tu = None
assert tu == None
def test_cursor(self):
path = os.path.join(kInputsDir, 'hello.cpp')
tu = get_tu(path)
c = tu.cursor
self.assertIsInstance(c, Cursor)
self.assertIs(c.kind, CursorKind.TRANSLATION_UNIT)
def test_parse_arguments(self):
path = os.path.join(kInputsDir, 'parse_arguments.c')
tu = TranslationUnit.from_source(path, ['-DDECL_ONE=hello', '-DDECL_TWO=hi'])
spellings = [c.spelling for c in tu.cursor.get_children()]
self.assertEqual(spellings[-2], 'hello')
self.assertEqual(spellings[-1], 'hi')
def test_reparse_arguments(self):
path = os.path.join(kInputsDir, 'parse_arguments.c')
tu = TranslationUnit.from_source(path, ['-DDECL_ONE=hello', '-DDECL_TWO=hi'])
tu.reparse()
spellings = [c.spelling for c in tu.cursor.get_children()]
self.assertEqual(spellings[-2], 'hello')
self.assertEqual(spellings[-1], 'hi')
def test_unsaved_files(self):
tu = TranslationUnit.from_source('fake.c', ['-I./'], unsaved_files = [
('fake.c', """
#include "fake.h"
int x;
int SOME_DEFINE;
"""),
('./fake.h', """
#define SOME_DEFINE y
""")
])
spellings = [c.spelling for c in tu.cursor.get_children()]
self.assertEqual(spellings[-2], 'x')
self.assertEqual(spellings[-1], 'y')
def test_unsaved_files_2(self):
try:
from StringIO import StringIO
except:
from io import StringIO
tu = TranslationUnit.from_source('fake.c', unsaved_files = [
('fake.c', StringIO('int x;'))])
spellings = [c.spelling for c in tu.cursor.get_children()]
self.assertEqual(spellings[-1], 'x')
def assert_normpaths_equal(self, path1, path2):
""" Compares two paths for equality after normalizing them with
os.path.normpath
"""
self.assertEqual(os.path.normpath(path1),
os.path.normpath(path2))
def test_includes(self):
def eq(expected, actual):
if not actual.is_input_file:
self.assert_normpaths_equal(expected[0], actual.source.name)
self.assert_normpaths_equal(expected[1], actual.include.name)
else:
self.assert_normpaths_equal(expected[1], actual.include.name)
src = os.path.join(kInputsDir, 'include.cpp')
h1 = os.path.join(kInputsDir, "header1.h")
h2 = os.path.join(kInputsDir, "header2.h")
h3 = os.path.join(kInputsDir, "header3.h")
inc = [(src, h1), (h1, h3), (src, h2), (h2, h3)]
tu = TranslationUnit.from_source(src)
for i in zip(inc, tu.get_includes()):
eq(i[0], i[1])
def test_save(self):
"""Ensure TranslationUnit.save() works."""
tu = get_tu('int foo();')
path = save_tu(tu)
self.assertTrue(os.path.exists(path))
self.assertGreater(os.path.getsize(path), 0)
os.unlink(path)
def test_save_translation_errors(self):
"""Ensure that saving to an invalid directory raises."""
tu = get_tu('int foo();')
path = '/does/not/exist/llvm-test.ast'
self.assertFalse(os.path.exists(os.path.dirname(path)))
with self.assertRaises(TranslationUnitSaveError) as cm:
tu.save(path)
ex = cm.exception
expected = TranslationUnitSaveError.ERROR_UNKNOWN
self.assertEqual(ex.save_error, expected)
def test_load(self):
"""Ensure TranslationUnits can be constructed from saved files."""
tu = get_tu('int foo();')
self.assertEqual(len(tu.diagnostics), 0)
path = save_tu(tu)
self.assertTrue(os.path.exists(path))
self.assertGreater(os.path.getsize(path), 0)
tu2 = TranslationUnit.from_ast_file(filename=path)
self.assertEqual(len(tu2.diagnostics), 0)
foo = get_cursor(tu2, 'foo')
self.assertIsNotNone(foo)
# Just in case there is an open file descriptor somewhere.
del tu2
os.unlink(path)
def test_index_parse(self):
path = os.path.join(kInputsDir, 'hello.cpp')
index = Index.create()
tu = index.parse(path)
self.assertIsInstance(tu, TranslationUnit)
def test_get_file(self):
"""Ensure tu.get_file() works appropriately."""
tu = get_tu('int foo();')
f = tu.get_file('t.c')
self.assertIsInstance(f, File)
self.assertEqual(f.name, 't.c')
with self.assertRaises(Exception):
f = tu.get_file('foobar.cpp')
def test_get_source_location(self):
"""Ensure tu.get_source_location() works."""
tu = get_tu('int foo();')
location = tu.get_location('t.c', 2)
self.assertIsInstance(location, SourceLocation)
self.assertEqual(location.offset, 2)
self.assertEqual(location.file.name, 't.c')
location = tu.get_location('t.c', (1, 3))
self.assertIsInstance(location, SourceLocation)
self.assertEqual(location.line, 1)
self.assertEqual(location.column, 3)
self.assertEqual(location.file.name, 't.c')
def test_get_source_range(self):
"""Ensure tu.get_source_range() works."""
tu = get_tu('int foo();')
r = tu.get_extent('t.c', (1,4))
self.assertIsInstance(r, SourceRange)
self.assertEqual(r.start.offset, 1)
self.assertEqual(r.end.offset, 4)
self.assertEqual(r.start.file.name, 't.c')
self.assertEqual(r.end.file.name, 't.c')
r = tu.get_extent('t.c', ((1,2), (1,3)))
self.assertIsInstance(r, SourceRange)
self.assertEqual(r.start.line, 1)
self.assertEqual(r.start.column, 2)
self.assertEqual(r.end.line, 1)
self.assertEqual(r.end.column, 3)
self.assertEqual(r.start.file.name, 't.c')
self.assertEqual(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))
self.assertIsInstance(r, SourceRange)
self.assertEqual(r.start.offset, 0)
self.assertEqual(r.end.offset, 5)
self.assertEqual(r.start.file.name, 't.c')
self.assertEqual(r.end.file.name, 't.c')
def test_get_tokens_gc(self):
"""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))
self.assertEqual(tokens[0].spelling, 'int')
gc.collect()
self.assertEqual(tokens[0].spelling, 'int')
del tokens[1]
gc.collect()
self.assertEqual(tokens[0].spelling, 'int')
# May trigger segfault if we don't do our job properly.
del tokens
gc.collect()
gc.collect() # Just in case.
def test_fail_from_source(self):
path = os.path.join(kInputsDir, 'non-existent.cpp')
try:
tu = TranslationUnit.from_source(path)
except TranslationUnitLoadError:
tu = None
self.assertEqual(tu, None)
def test_fail_from_ast_file(self):
path = os.path.join(kInputsDir, 'non-existent.ast')
try:
tu = TranslationUnit.from_ast_file(path)
except TranslationUnitLoadError:
tu = None
self.assertEqual(tu, None)

View File

@ -1,12 +1,13 @@
import gc
import unittest
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
from .util import get_tu
kInput = """\
typedef int I;
@ -24,400 +25,414 @@
"""
def test_a_struct():
tu = get_tu(kInput)
teststruct = get_cursor(tu, 'teststruct')
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()
assert fields[0].type.kind == TypeKind.INT
assert fields[0].type.get_canonical().kind == TypeKind.INT
assert fields[0].type.get_typedef_name() == ''
assert fields[1].spelling == 'b'
assert not fields[1].type.is_const_qualified()
assert fields[1].type.kind == TypeKind.TYPEDEF
assert fields[1].type.get_canonical().kind == TypeKind.INT
assert fields[1].type.get_declaration().spelling == 'I'
assert fields[1].type.get_typedef_name() == 'I'
assert fields[2].spelling == 'c'
assert not fields[2].type.is_const_qualified()
assert fields[2].type.kind == TypeKind.LONG
assert fields[2].type.get_canonical().kind == TypeKind.LONG
assert fields[2].type.get_typedef_name() == ''
assert fields[3].spelling == 'd'
assert not fields[3].type.is_const_qualified()
assert fields[3].type.kind == TypeKind.ULONG
assert fields[3].type.get_canonical().kind == TypeKind.ULONG
assert fields[3].type.get_typedef_name() == ''
assert fields[4].spelling == 'e'
assert not fields[4].type.is_const_qualified()
assert fields[4].type.kind == TypeKind.LONG
assert fields[4].type.get_canonical().kind == TypeKind.LONG
assert fields[4].type.get_typedef_name() == ''
assert fields[5].spelling == 'f'
assert fields[5].type.is_const_qualified()
assert fields[5].type.kind == TypeKind.INT
assert fields[5].type.get_canonical().kind == TypeKind.INT
assert fields[5].type.get_typedef_name() == ''
assert fields[6].spelling == 'g'
assert not fields[6].type.is_const_qualified()
assert fields[6].type.kind == TypeKind.POINTER
assert fields[6].type.get_pointee().kind == TypeKind.INT
assert fields[6].type.get_typedef_name() == ''
assert fields[7].spelling == 'h'
assert not fields[7].type.is_const_qualified()
assert fields[7].type.kind == TypeKind.POINTER
assert fields[7].type.get_pointee().kind == TypeKind.POINTER
assert fields[7].type.get_pointee().get_pointee().kind == TypeKind.POINTER
assert fields[7].type.get_pointee().get_pointee().get_pointee().kind == TypeKind.INT
assert fields[7].type.get_typedef_name() == ''
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];
};
"""
def testConstantArray():
tu = get_tu(constarrayInput)
teststruct = get_cursor(tu, 'teststruct')
assert teststruct is not None, "Didn't find teststruct??"
fields = list(teststruct.get_children())
assert fields[0].spelling == 'A'
assert fields[0].type.kind == TypeKind.CONSTANTARRAY
assert fields[0].type.get_array_element_type() is not None
assert fields[0].type.get_array_element_type().kind == TypeKind.POINTER
assert fields[0].type.get_array_size() == 2
def test_equal():
"""Ensure equivalence operators work on Type."""
source = 'int a; int b; void *v;'
tu = get_tu(source)
class TestType(unittest.TestCase):
def test_a_struct(self):
tu = get_tu(kInput)
a = get_cursor(tu, 'a')
b = get_cursor(tu, 'b')
v = get_cursor(tu, 'v')
assert a is not None
assert b is not None
assert v is not None
assert a.type == b.type
assert a.type != v.type
assert a.type != None
assert a.type != 'foo'
def test_type_spelling():
"""Ensure Type.spelling works."""
tu = get_tu('int c[5]; void f(int i[]); int x; int v[x];')
c = get_cursor(tu, 'c')
i = get_cursor(tu, 'i')
x = get_cursor(tu, 'x')
v = get_cursor(tu, 'v')
assert c is not None
assert i is not None
assert x is not None
assert v is not None
assert c.type.spelling == "int [5]"
assert i.type.spelling == "int []"
assert x.type.spelling == "int"
assert v.type.spelling == "int [x]"
def test_typekind_spelling():
"""Ensure TypeKind.spelling works."""
tu = get_tu('int a;')
a = get_cursor(tu, 'a')
assert a is not None
assert a.type.kind.spelling == 'Int'
def test_function_argument_types():
"""Ensure that Type.argument_types() works as expected."""
tu = get_tu('void f(int, int);')
f = get_cursor(tu, 'f')
assert f is not None
args = f.type.argument_types()
assert args is not None
assert len(args) == 2
t0 = args[0]
assert t0 is not None
assert t0.kind == TypeKind.INT
t1 = args[1]
assert t1 is not None
assert t1.kind == TypeKind.INT
args2 = list(args)
assert len(args2) == 2
assert t0 == args2[0]
assert t1 == args2[1]
@raises(TypeError)
def test_argument_types_string_key():
"""Ensure that non-int keys raise a TypeError."""
tu = get_tu('void f(int, int);')
f = get_cursor(tu, 'f')
assert f is not None
args = f.type.argument_types()
assert len(args) == 2
args['foo']
@raises(IndexError)
def test_argument_types_negative_index():
"""Ensure that negative indexes on argument_types Raises an IndexError."""
tu = get_tu('void f(int, int);')
f = get_cursor(tu, 'f')
args = f.type.argument_types()
args[-1]
@raises(IndexError)
def test_argument_types_overflow_index():
"""Ensure that indexes beyond the length of Type.argument_types() raise."""
tu = get_tu('void f(int, int);')
f = get_cursor(tu, 'f')
args = f.type.argument_types()
args[2]
@raises(Exception)
def test_argument_types_invalid_type():
"""Ensure that obtaining argument_types on a Type without them raises."""
tu = get_tu('int i;')
i = get_cursor(tu, 'i')
assert i is not None
i.type.argument_types()
def test_is_pod():
"""Ensure Type.is_pod() works."""
tu = get_tu('int i; void f();')
i = get_cursor(tu, 'i')
f = get_cursor(tu, 'f')
assert i is not None
assert f is not None
assert i.type.is_pod()
assert not f.type.is_pod()
def test_function_variadic():
"""Ensure Type.is_function_variadic works."""
source ="""
#include <stdarg.h>
void foo(int a, ...);
void bar(int a, int b);
"""
tu = get_tu(source)
foo = get_cursor(tu, 'foo')
bar = get_cursor(tu, 'bar')
assert foo is not None
assert bar is not None
assert isinstance(foo.type.is_function_variadic(), bool)
assert foo.type.is_function_variadic()
assert not bar.type.is_function_variadic()
def test_element_type():
"""Ensure Type.element_type works."""
tu = get_tu('int c[5]; void f(int i[]); int x; int v[x];')
c = get_cursor(tu, 'c')
i = get_cursor(tu, 'i')
v = get_cursor(tu, 'v')
assert c is not None
assert i is not None
assert v is not None
assert c.type.kind == TypeKind.CONSTANTARRAY
assert c.type.element_type.kind == TypeKind.INT
assert i.type.kind == TypeKind.INCOMPLETEARRAY
assert i.type.element_type.kind == TypeKind.INT
assert v.type.kind == TypeKind.VARIABLEARRAY
assert v.type.element_type.kind == TypeKind.INT
@raises(Exception)
def test_invalid_element_type():
"""Ensure Type.element_type raises if type doesn't have elements."""
tu = get_tu('int i;')
i = get_cursor(tu, 'i')
assert i is not None
i.element_type
def test_element_count():
"""Ensure Type.element_count works."""
tu = get_tu('int i[5]; int j;')
i = get_cursor(tu, 'i')
j = get_cursor(tu, 'j')
assert i is not None
assert j is not None
assert i.type.element_count == 5
try:
j.type.element_count
assert False
except:
assert True
def test_is_volatile_qualified():
"""Ensure Type.is_volatile_qualified works."""
tu = get_tu('volatile int i = 4; int j = 2;')
i = get_cursor(tu, 'i')
j = get_cursor(tu, 'j')
assert i is not None
assert j is not None
assert isinstance(i.type.is_volatile_qualified(), bool)
assert i.type.is_volatile_qualified()
assert not j.type.is_volatile_qualified()
def test_is_restrict_qualified():
"""Ensure Type.is_restrict_qualified works."""
tu = get_tu('struct s { void * restrict i; void * j; };')
i = get_cursor(tu, 'i')
j = get_cursor(tu, 'j')
assert i is not None
assert j is not None
assert isinstance(i.type.is_restrict_qualified(), bool)
assert i.type.is_restrict_qualified()
assert not j.type.is_restrict_qualified()
def test_record_layout():
"""Ensure Cursor.type.get_size, Cursor.type.get_align and
Cursor.type.get_offset works."""
source ="""
struct a {
long a1;
long a2:3;
long a3:4;
long long a4;
};
"""
tries=[(['-target','i386-linux-gnu'],(4,16,0,32,35,64)),
(['-target','nvptx64-unknown-unknown'],(8,24,0,64,67,128)),
(['-target','i386-pc-win32'],(8,16,0,32,35,64)),
(['-target','msp430-none-none'],(2,14,0,32,35,48))]
for flags, values in tries:
align,total,a1,a2,a3,a4 = values
tu = get_tu(source, flags=flags)
teststruct = get_cursor(tu, 'a')
teststruct = get_cursor(tu, 'teststruct')
self.assertIsNotNone(teststruct, "Could not find teststruct.")
fields = list(teststruct.get_children())
assert teststruct.type.get_align() == align
assert teststruct.type.get_size() == total
assert teststruct.type.get_offset(fields[0].spelling) == a1
assert teststruct.type.get_offset(fields[1].spelling) == a2
assert teststruct.type.get_offset(fields[2].spelling) == a3
assert teststruct.type.get_offset(fields[3].spelling) == a4
assert fields[0].is_bitfield() == False
assert fields[1].is_bitfield() == True
assert fields[1].get_bitfield_width() == 3
assert fields[2].is_bitfield() == True
assert fields[2].get_bitfield_width() == 4
assert fields[3].is_bitfield() == False
self.assertEqual(fields[0].kind, CursorKind.FIELD_DECL)
self.assertIsNotNone(fields[0].translation_unit)
self.assertEqual(fields[0].spelling, 'a')
self.assertFalse(fields[0].type.is_const_qualified())
self.assertEqual(fields[0].type.kind, TypeKind.INT)
self.assertEqual(fields[0].type.get_canonical().kind, TypeKind.INT)
self.assertEqual(fields[0].type.get_typedef_name(), '')
def test_offset():
"""Ensure Cursor.get_record_field_offset works in anonymous records"""
source="""
struct Test {
struct {int a;} typeanon;
struct {
int bariton;
union {
int foo;
};
};
int bar;
};"""
tries=[(['-target','i386-linux-gnu'],(4,16,0,32,64,96)),
(['-target','nvptx64-unknown-unknown'],(8,24,0,32,64,96)),
(['-target','i386-pc-win32'],(8,16,0,32,64,96)),
(['-target','msp430-none-none'],(2,14,0,32,64,96))]
for flags, values in tries:
align,total,f1,bariton,foo,bar = values
self.assertEqual(fields[1].kind, CursorKind.FIELD_DECL)
self.assertIsNotNone(fields[1].translation_unit)
self.assertEqual(fields[1].spelling, 'b')
self.assertFalse(fields[1].type.is_const_qualified())
self.assertEqual(fields[1].type.kind, TypeKind.TYPEDEF)
self.assertEqual(fields[1].type.get_canonical().kind, TypeKind.INT)
self.assertEqual(fields[1].type.get_declaration().spelling, 'I')
self.assertEqual(fields[1].type.get_typedef_name(), 'I')
self.assertEqual(fields[2].kind, CursorKind.FIELD_DECL)
self.assertIsNotNone(fields[2].translation_unit)
self.assertEqual(fields[2].spelling, 'c')
self.assertFalse(fields[2].type.is_const_qualified())
self.assertEqual(fields[2].type.kind, TypeKind.LONG)
self.assertEqual(fields[2].type.get_canonical().kind, TypeKind.LONG)
self.assertEqual(fields[2].type.get_typedef_name(), '')
self.assertEqual(fields[3].kind, CursorKind.FIELD_DECL)
self.assertIsNotNone(fields[3].translation_unit)
self.assertEqual(fields[3].spelling, 'd')
self.assertFalse(fields[3].type.is_const_qualified())
self.assertEqual(fields[3].type.kind, TypeKind.ULONG)
self.assertEqual(fields[3].type.get_canonical().kind, TypeKind.ULONG)
self.assertEqual(fields[3].type.get_typedef_name(), '')
self.assertEqual(fields[4].kind, CursorKind.FIELD_DECL)
self.assertIsNotNone(fields[4].translation_unit)
self.assertEqual(fields[4].spelling, 'e')
self.assertFalse(fields[4].type.is_const_qualified())
self.assertEqual(fields[4].type.kind, TypeKind.LONG)
self.assertEqual(fields[4].type.get_canonical().kind, TypeKind.LONG)
self.assertEqual(fields[4].type.get_typedef_name(), '')
self.assertEqual(fields[5].kind, CursorKind.FIELD_DECL)
self.assertIsNotNone(fields[5].translation_unit)
self.assertEqual(fields[5].spelling, 'f')
self.assertTrue(fields[5].type.is_const_qualified())
self.assertEqual(fields[5].type.kind, TypeKind.INT)
self.assertEqual(fields[5].type.get_canonical().kind, TypeKind.INT)
self.assertEqual(fields[5].type.get_typedef_name(), '')
self.assertEqual(fields[6].kind, CursorKind.FIELD_DECL)
self.assertIsNotNone(fields[6].translation_unit)
self.assertEqual(fields[6].spelling, 'g')
self.assertFalse(fields[6].type.is_const_qualified())
self.assertEqual(fields[6].type.kind, TypeKind.POINTER)
self.assertEqual(fields[6].type.get_pointee().kind, TypeKind.INT)
self.assertEqual(fields[6].type.get_typedef_name(), '')
self.assertEqual(fields[7].kind, CursorKind.FIELD_DECL)
self.assertIsNotNone(fields[7].translation_unit)
self.assertEqual(fields[7].spelling, 'h')
self.assertFalse(fields[7].type.is_const_qualified())
self.assertEqual(fields[7].type.kind, TypeKind.POINTER)
self.assertEqual(fields[7].type.get_pointee().kind, TypeKind.POINTER)
self.assertEqual(fields[7].type.get_pointee().get_pointee().kind, TypeKind.POINTER)
self.assertEqual(fields[7].type.get_pointee().get_pointee().get_pointee().kind, TypeKind.INT)
self.assertEqual(fields[7].type.get_typedef_name(), '')
def test_references(self):
"""Ensure that a Type maintains a reference to a TranslationUnit."""
tu = get_tu('int x;')
children = list(tu.cursor.get_children())
self.assertGreater(len(children), 0)
cursor = children[0]
t = cursor.type
self.assertIsInstance(t.translation_unit, TranslationUnit)
# Delete main TranslationUnit reference and force a GC.
del tu
gc.collect()
self.assertIsInstance(t.translation_unit, TranslationUnit)
# If the TU was destroyed, this should cause a segfault.
decl = t.get_declaration()
def testConstantArray(self):
tu = get_tu(constarrayInput)
teststruct = get_cursor(tu, 'teststruct')
self.assertIsNotNone(teststruct, "Didn't find teststruct??")
fields = list(teststruct.get_children())
self.assertEqual(fields[0].spelling, 'A')
self.assertEqual(fields[0].type.kind, TypeKind.CONSTANTARRAY)
self.assertIsNotNone(fields[0].type.get_array_element_type())
self.assertEqual(fields[0].type.get_array_element_type().kind, TypeKind.POINTER)
self.assertEqual(fields[0].type.get_array_size(), 2)
def test_equal(self):
"""Ensure equivalence operators work on Type."""
source = 'int a; int b; void *v;'
tu = get_tu(source)
teststruct = get_cursor(tu, 'Test')
children = list(teststruct.get_children())
fields = list(teststruct.type.get_fields())
assert children[0].kind == CursorKind.STRUCT_DECL
assert children[0].spelling != "typeanon"
assert children[1].spelling == "typeanon"
assert fields[0].kind == CursorKind.FIELD_DECL
assert fields[1].kind == CursorKind.FIELD_DECL
assert fields[1].is_anonymous()
assert teststruct.type.get_offset("typeanon") == f1
assert teststruct.type.get_offset("bariton") == bariton
assert teststruct.type.get_offset("foo") == foo
assert teststruct.type.get_offset("bar") == bar
a = get_cursor(tu, 'a')
b = get_cursor(tu, 'b')
v = get_cursor(tu, 'v')
def test_decay():
"""Ensure decayed types are handled as the original type"""
self.assertIsNotNone(a)
self.assertIsNotNone(b)
self.assertIsNotNone(v)
tu = get_tu("void foo(int a[]);")
foo = get_cursor(tu, 'foo')
a = foo.type.argument_types()[0]
self.assertEqual(a.type, b.type)
self.assertNotEqual(a.type, v.type)
assert a.kind == TypeKind.INCOMPLETEARRAY
assert a.element_type.kind == TypeKind.INT
assert a.get_canonical().kind == TypeKind.INCOMPLETEARRAY
self.assertNotEqual(a.type, None)
self.assertNotEqual(a.type, 'foo')
def test_addrspace():
"""Ensure the address space can be queried"""
tu = get_tu('__attribute__((address_space(2))) int testInteger = 3;', 'c')
def test_type_spelling(self):
"""Ensure Type.spelling works."""
tu = get_tu('int c[5]; void f(int i[]); int x; int v[x];')
c = get_cursor(tu, 'c')
i = get_cursor(tu, 'i')
x = get_cursor(tu, 'x')
v = get_cursor(tu, 'v')
self.assertIsNotNone(c)
self.assertIsNotNone(i)
self.assertIsNotNone(x)
self.assertIsNotNone(v)
self.assertEqual(c.type.spelling, "int [5]")
self.assertEqual(i.type.spelling, "int []")
self.assertEqual(x.type.spelling, "int")
self.assertEqual(v.type.spelling, "int [x]")
testInteger = get_cursor(tu, 'testInteger')
def test_typekind_spelling(self):
"""Ensure TypeKind.spelling works."""
tu = get_tu('int a;')
a = get_cursor(tu, 'a')
assert testInteger is not None, "Could not find testInteger."
assert testInteger.type.get_address_space() == 2
self.assertIsNotNone(a)
self.assertEqual(a.type.kind.spelling, 'Int')
def test_function_argument_types(self):
"""Ensure that Type.argument_types() works as expected."""
tu = get_tu('void f(int, int);')
f = get_cursor(tu, 'f')
self.assertIsNotNone(f)
args = f.type.argument_types()
self.assertIsNotNone(args)
self.assertEqual(len(args), 2)
t0 = args[0]
self.assertIsNotNone(t0)
self.assertEqual(t0.kind, TypeKind.INT)
t1 = args[1]
self.assertIsNotNone(t1)
self.assertEqual(t1.kind, TypeKind.INT)
args2 = list(args)
self.assertEqual(len(args2), 2)
self.assertEqual(t0, args2[0])
self.assertEqual(t1, args2[1])
def test_argument_types_string_key(self):
"""Ensure that non-int keys raise a TypeError."""
tu = get_tu('void f(int, int);')
f = get_cursor(tu, 'f')
self.assertIsNotNone(f)
args = f.type.argument_types()
self.assertEqual(len(args), 2)
with self.assertRaises(TypeError):
args['foo']
def test_argument_types_negative_index(self):
"""Ensure that negative indexes on argument_types Raises an IndexError."""
tu = get_tu('void f(int, int);')
f = get_cursor(tu, 'f')
args = f.type.argument_types()
with self.assertRaises(IndexError):
args[-1]
def test_argument_types_overflow_index(self):
"""Ensure that indexes beyond the length of Type.argument_types() raise."""
tu = get_tu('void f(int, int);')
f = get_cursor(tu, 'f')
args = f.type.argument_types()
with self.assertRaises(IndexError):
args[2]
def test_argument_types_invalid_type(self):
"""Ensure that obtaining argument_types on a Type without them raises."""
tu = get_tu('int i;')
i = get_cursor(tu, 'i')
self.assertIsNotNone(i)
with self.assertRaises(Exception):
i.type.argument_types()
def test_is_pod(self):
"""Ensure Type.is_pod() works."""
tu = get_tu('int i; void f();')
i = get_cursor(tu, 'i')
f = get_cursor(tu, 'f')
self.assertIsNotNone(i)
self.assertIsNotNone(f)
self.assertTrue(i.type.is_pod())
self.assertFalse(f.type.is_pod())
def test_function_variadic(self):
"""Ensure Type.is_function_variadic works."""
source ="""
#include <stdarg.h>
void foo(int a, ...);
void bar(int a, int b);
"""
tu = get_tu(source)
foo = get_cursor(tu, 'foo')
bar = get_cursor(tu, 'bar')
self.assertIsNotNone(foo)
self.assertIsNotNone(bar)
self.assertIsInstance(foo.type.is_function_variadic(), bool)
self.assertTrue(foo.type.is_function_variadic())
self.assertFalse(bar.type.is_function_variadic())
def test_element_type(self):
"""Ensure Type.element_type works."""
tu = get_tu('int c[5]; void f(int i[]); int x; int v[x];')
c = get_cursor(tu, 'c')
i = get_cursor(tu, 'i')
v = get_cursor(tu, 'v')
self.assertIsNotNone(c)
self.assertIsNotNone(i)
self.assertIsNotNone(v)
self.assertEqual(c.type.kind, TypeKind.CONSTANTARRAY)
self.assertEqual(c.type.element_type.kind, TypeKind.INT)
self.assertEqual(i.type.kind, TypeKind.INCOMPLETEARRAY)
self.assertEqual(i.type.element_type.kind, TypeKind.INT)
self.assertEqual(v.type.kind, TypeKind.VARIABLEARRAY)
self.assertEqual(v.type.element_type.kind, TypeKind.INT)
def test_invalid_element_type(self):
"""Ensure Type.element_type raises if type doesn't have elements."""
tu = get_tu('int i;')
i = get_cursor(tu, 'i')
self.assertIsNotNone(i)
with self.assertRaises(Exception):
i.element_type
def test_element_count(self):
"""Ensure Type.element_count works."""
tu = get_tu('int i[5]; int j;')
i = get_cursor(tu, 'i')
j = get_cursor(tu, 'j')
self.assertIsNotNone(i)
self.assertIsNotNone(j)
self.assertEqual(i.type.element_count, 5)
with self.assertRaises(Exception):
j.type.element_count
def test_is_volatile_qualified(self):
"""Ensure Type.is_volatile_qualified works."""
tu = get_tu('volatile int i = 4; int j = 2;')
i = get_cursor(tu, 'i')
j = get_cursor(tu, 'j')
self.assertIsNotNone(i)
self.assertIsNotNone(j)
self.assertIsInstance(i.type.is_volatile_qualified(), bool)
self.assertTrue(i.type.is_volatile_qualified())
self.assertFalse(j.type.is_volatile_qualified())
def test_is_restrict_qualified(self):
"""Ensure Type.is_restrict_qualified works."""
tu = get_tu('struct s { void * restrict i; void * j; };')
i = get_cursor(tu, 'i')
j = get_cursor(tu, 'j')
self.assertIsNotNone(i)
self.assertIsNotNone(j)
self.assertIsInstance(i.type.is_restrict_qualified(), bool)
self.assertTrue(i.type.is_restrict_qualified())
self.assertFalse(j.type.is_restrict_qualified())
def test_record_layout(self):
"""Ensure Cursor.type.get_size, Cursor.type.get_align and
Cursor.type.get_offset works."""
source ="""
struct a {
long a1;
long a2:3;
long a3:4;
long long a4;
};
"""
tries=[(['-target','i386-linux-gnu'],(4,16,0,32,35,64)),
(['-target','nvptx64-unknown-unknown'],(8,24,0,64,67,128)),
(['-target','i386-pc-win32'],(8,16,0,32,35,64)),
(['-target','msp430-none-none'],(2,14,0,32,35,48))]
for flags, values in tries:
align,total,a1,a2,a3,a4 = values
tu = get_tu(source, flags=flags)
teststruct = get_cursor(tu, 'a')
fields = list(teststruct.get_children())
self.assertEqual(teststruct.type.get_align(), align)
self.assertEqual(teststruct.type.get_size(), total)
self.assertEqual(teststruct.type.get_offset(fields[0].spelling), a1)
self.assertEqual(teststruct.type.get_offset(fields[1].spelling), a2)
self.assertEqual(teststruct.type.get_offset(fields[2].spelling), a3)
self.assertEqual(teststruct.type.get_offset(fields[3].spelling), a4)
self.assertEqual(fields[0].is_bitfield(), False)
self.assertEqual(fields[1].is_bitfield(), True)
self.assertEqual(fields[1].get_bitfield_width(), 3)
self.assertEqual(fields[2].is_bitfield(), True)
self.assertEqual(fields[2].get_bitfield_width(), 4)
self.assertEqual(fields[3].is_bitfield(), False)
def test_offset(self):
"""Ensure Cursor.get_record_field_offset works in anonymous records"""
source="""
struct Test {
struct {int a;} typeanon;
struct {
int bariton;
union {
int foo;
};
};
int bar;
};"""
tries=[(['-target','i386-linux-gnu'],(4,16,0,32,64,96)),
(['-target','nvptx64-unknown-unknown'],(8,24,0,32,64,96)),
(['-target','i386-pc-win32'],(8,16,0,32,64,96)),
(['-target','msp430-none-none'],(2,14,0,32,64,96))]
for flags, values in tries:
align,total,f1,bariton,foo,bar = values
tu = get_tu(source)
teststruct = get_cursor(tu, 'Test')
children = list(teststruct.get_children())
fields = list(teststruct.type.get_fields())
self.assertEqual(children[0].kind, CursorKind.STRUCT_DECL)
self.assertNotEqual(children[0].spelling, "typeanon")
self.assertEqual(children[1].spelling, "typeanon")
self.assertEqual(fields[0].kind, CursorKind.FIELD_DECL)
self.assertEqual(fields[1].kind, CursorKind.FIELD_DECL)
self.assertTrue(fields[1].is_anonymous())
self.assertEqual(teststruct.type.get_offset("typeanon"), f1)
self.assertEqual(teststruct.type.get_offset("bariton"), bariton)
self.assertEqual(teststruct.type.get_offset("foo"), foo)
self.assertEqual(teststruct.type.get_offset("bar"), bar)
def test_decay(self):
"""Ensure decayed types are handled as the original type"""
tu = get_tu("void foo(int a[]);")
foo = get_cursor(tu, 'foo')
a = foo.type.argument_types()[0]
self.assertEqual(a.kind, TypeKind.INCOMPLETEARRAY)
self.assertEqual(a.element_type.kind, TypeKind.INT)
self.assertEqual(a.get_canonical().kind, TypeKind.INCOMPLETEARRAY)
def test_addrspace(self):
"""Ensure the address space can be queried"""
tu = get_tu('__attribute__((address_space(2))) int testInteger = 3;', 'c')
testInteger = get_cursor(tu, 'testInteger')
self.assertIsNotNone(testInteger, "Could not find testInteger.")
self.assertEqual(testInteger.type.get_address_space(), 2)

View File

@ -0,0 +1,52 @@
set(LLVM_TARGETS_TO_BUILD X86;ARM;AArch64 CACHE STRING "")
set(CLANG_VENDOR Android CACHE STRING "")
set(CMAKE_BUILD_TYPE Release CACHE STRING "")
set(LLVM_ENABLE_THREADS OFF CACHE BOOL "")
set(LLVM_ENABLE_ASSERTIONS ON CACHE BOOL "")
set(LLVM_LIBDIR_SUFFIX 64 CACHE STRING "")
set(LLVM_ENABLE_LIBCXX ON CACHE BOOL "")
set(ANDROID_RUNTIMES_ENABLE_ASSERTIONS ON CACHE BOOL "")
set(ANDROID_RUNTIMES_BUILD_TYPE Release CACHE STRING "")
set(ANDROID_BUILTINS_BUILD_TYPE Release CACHE STRING "")
set(LLVM_BUILTIN_TARGETS "i686-linux-android;x86_64-linux-android;aarch64-linux-android;armv7-linux-android" CACHE STRING "")
foreach(target i686;x86_64;aarch64;armv7)
set(BUILTINS_${target}-linux-android_ANDROID 1 CACHE STRING "")
set(BUILTINS_${target}-linux-android_CMAKE_BUILD_TYPE ${ANDROID_BUILTINS_BUILD_TYPE} CACHE STRING "")
set(BUILTINS_${target}-linux-android_CMAKE_ASM_FLAGS ${ANDROID_${target}_C_FLAGS} CACHE PATH "")
set(BUILTINS_${target}-linux-android_CMAKE_C_FLAGS ${ANDROID_${target}_C_FLAGS} CACHE PATH "")
set(BUILTINS_${target}-linux-android_CMAKE_SYSROOT ${ANDROID_${target}_SYSROOT} CACHE PATH "")
set(BUILTINS_${target}-linux-android_CMAKE_EXE_LINKER_FLAGS ${ANDROID_${target}_LINKER_FLAGS} CACHE PATH "")
set(BUILTINS_${target}-linux-android_CMAKE_SHARED_LINKER_FLAGS ${ANDROID_${target}_LINKER_FLAGS} CACHE PATH "")
set(BUILTINS_${target}-linux-android_CMAKE_MOUDLE_LINKER_FLAGS ${ANDROID_${target}_LINKER_FLAGS} CACHE PATH "")
endforeach()
set(LLVM_RUNTIME_TARGETS "i686-linux-android;x86_64-linux-android;aarch64-linux-android;armv7-linux-android" CACHE STRING "")
foreach(target i686;x86_64;aarch64;armv7)
set(RUNTIMES_${target}-linux-android_ANDROID 1 CACHE STRING "")
set(RUNTIMES_${target}-linux-android_CMAKE_ASM_FLAGS ${ANDROID_${target}_C_FLAGS} CACHE PATH "")
set(RUNTIMES_${target}-linux-android_CMAKE_BUILD_TYPE ${ANDROID_RUNTIMES_BUILD_TYPE} CACHE STRING "")
set(RUNTIMES_${target}-linux-android_CMAKE_C_FLAGS ${ANDROID_${target}_C_FLAGS} CACHE PATH "")
set(RUNTIMES_${target}-linux-android_CMAKE_CXX_FLAGS ${ANDROID_${target}_CXX_FLAGS} CACHE PATH "")
set(RUNTIMES_${target}-linux-android_CMAKE_SYSROOT ${ANDROID_${target}_SYSROOT} CACHE PATH "")
set(RUNTIMES_${target}-linux-android_CMAKE_EXE_LINKER_FLAGS ${ANDROID_${target}_LINKER_FLAGS} CACHE PATH "")
set(RUNTIMES_${target}-linux-android_CMAKE_SHARED_LINKER_FLAGS ${ANDROID_${target}_LINKER_FLAGS} CACHE PATH "")
set(RUNTIMES_${target}-linux-android_CMAKE_MODULE_LINKER_FLAGS ${ANDROID_${target}_LINKER_FLAGS} CACHE PATH "")
set(RUNTIMES_${target}-linux-android_COMPILER_RT_ENABLE_WERROR ON CACHE BOOL "")
set(RUNTIMES_${target}-linux-android_COMPILER_RT_TEST_COMPILER_CFLAGS ${ANDROID_${target}_C_FLAGS} CACHE PATH "")
set(RUNTIMES_${target}-linux-android_COMPILER_RT_INCLUDE_TESTS OFF CACHE BOOL "")
set(RUNTIMES_${target}-linux-android_LLVM_ENABLE_ASSERTIONS ${ANDROID_RUNTIMES_ENABLE_ASSERTIONS} CACHE BOOL "")
set(RUNTIMES_${target}-linux-android_LLVM_ENABLE_LIBCXX ON CACHE BOOL "")
set(RUNTIMES_${target}-linux-android_LLVM_ENABLE_THREADS OFF CACHE BOOL "")
set(RUNTIMES_${target}-linux-android_LLVM_INCLUDE_TESTS OFF CACHE BOOL "")
set(RUNTIMES_${target}-linux-android_LIBCXX_USE_COMPILER_RT ON CACHE BOOL "")
set(RUNTIMES_${target}-linux-android_LIBCXXABI_USE_COMPILER_RT ON CACHE BOOL "")
set(RUNTIMES_${target}-linux-android_LIBUNWIND_HAS_NO_EXCEPTIONS_FLAG ON CACHE BOOL "")
set(RUNTIMES_${target}-linux-android_LIBUNWIND_HAS_FUNWIND_TABLES ON CACHE BOOL "")
endforeach()
set(RUNTIMES_armv7-linux-android_LIBCXXABI_USE_LLVM_UNWINDER ON CACHE BOOL "")

View File

@ -0,0 +1,43 @@
# This file sets up a CMakeCache for an Android toolchain build.
set(LLVM_TARGETS_TO_BUILD X86 CACHE STRING "")
set(CLANG_ENABLE_ARCMT OFF CACHE BOOL "")
set(CLANG_ENABLE_STATIC_ANALYZER OFF CACHE BOOL "")
set(CLANG_VENDOR Android CACHE STRING "")
set(CMAKE_BUILD_TYPE RELEASE CACHE STRING "")
set(HAVE_LIBCXXABI ON CACHE BOOL "")
set(LLVM_BUILD_TOOLS OFF CACHE BOOL "")
set(LLVM_ENABLE_ASSERTIONS ON CACHE BOOL "")
set(LLVM_ENABLE_THREADS OFF CACHE BOOL "")
set(LLVM_LIBDIR_SUFFIX 64 CACHE STRING "")
set(LLVM_TOOL_CLANG_TOOLS_EXTRA_BUILD OFF CACHE BOOL "")
set(LLVM_TOOL_OPENMP_BUILD OFF CACHE BOOL "")
set(LLVM_ENABLE_LIBCXX ON CACHE BOOL "")
if (LIBCXX_ENABLE_ABI_LINKER_SCRIPT)
list(APPEND EXTRA_ARGS -DLIBCXX_ENABLE_ABI_LINKER_SCRIPT=${LIBCXX_ENABLE_ABI_LINKER_SCRIPT})
endif()
if (LIBCXX_ENABLE_STATIC_ABI_LIBRARY)
list(APPEND EXTRA_ARGS -DLIBCXX_ENABLE_STATIC_ABI_LIBRARY=${LIBCXX_ENABLE_STATIC_ABI_LIBRARY})
endif()
if (LLVM_BUILD_EXTERNAL_COMPILER_RT)
set(APPEND EXTRA_ARGS -DLLVM_BUILD_EXTERNAL_COMPILER_RT=${LLVM_BUILD_EXTERNAL_COMPILER_RT})
endif()
get_cmake_property(variableNames VARIABLES)
foreach(variableName ${variableNames})
if(variableName MATCHES "^STAGE2_")
string(REPLACE "STAGE2_" "" new_name ${variableName})
list(APPEND EXTRA_ARGS "-D${new_name}=${${variableName}}")
endif()
endforeach()
set(CLANG_ENABLE_BOOTSTRAP ON CACHE BOOL "")
set(CLANG_BOOTSTRAP_CMAKE_ARGS
${EXTRA_ARGS}
-C${CMAKE_CURRENT_LIST_DIR}/Android-stage2.cmake CACHE STRING "")

View File

@ -24,6 +24,12 @@ set(CLANG_BOOTSTRAP_PASSTHROUGH
CMAKE_OSX_ARCHITECTURES
CACHE STRING "")
# Disabling embedded darwin compiler-rt on stage1 builds is required because we
# don't build stage1 to support arm code generation.
set(COMPILER_RT_ENABLE_IOS OFF CACHE BOOL "")
set(COMPILER_RT_ENABLE_WATCHOS OFF CACHE BOOL "")
set(COMPILER_RT_ENABLE_TVOS OFF CACHE BOOL "")
set(BOOTSTRAP_LLVM_ENABLE_LTO ON CACHE BOOL "")
set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "")
@ -39,6 +45,8 @@ set(CLANG_BOOTSTRAP_TARGETS
clang-test-depends
distribution
install-distribution
install-xcode-toolchain
install-distribution-toolchain
clang CACHE STRING "")
#bootstrap

View File

@ -40,6 +40,10 @@ set(LIBCXX_INSTALL_HEADERS ON CACHE BOOL "")
set(LIBCXX_INCLUDE_TESTS OFF CACHE BOOL "")
set(LLVM_LTO_VERSION_OFFSET 3000 CACHE STRING "")
# Generating Xcode toolchains is useful for developers wanting to build and use
# clang without installing over existing tools.
set(LLVM_CREATE_XCODE_TOOLCHAIN ON CACHE BOOL "")
# setup toolchain
set(LLVM_INSTALL_TOOLCHAIN_ONLY ON CACHE BOOL "")
set(LLVM_TOOLCHAIN_TOOLS
@ -57,7 +61,7 @@ set(LLVM_DISTRIBUTION_COMPONENTS
LTO
clang-format
clang-headers
libcxx-headers
cxx-headers
${LLVM_TOOLCHAIN_TOOLS}
CACHE STRING "")

View File

@ -7,8 +7,9 @@ set(PACKAGE_VENDOR Fuchsia CACHE STRING "")
set(LLVM_INCLUDE_EXAMPLES OFF CACHE BOOL "")
set(LLVM_INCLUDE_DOCS OFF CACHE BOOL "")
set(LLVM_ENABLE_ZLIB ON CACHE BOOL "")
set(LLVM_ENABLE_BACKTRACES OFF CACHE BOOL "")
set(LLVM_ENABLE_TERMINFO OFF CACHE BOOL "")
set(LLVM_ENABLE_ZLIB ON CACHE BOOL "")
set(LLVM_EXTERNALIZE_DEBUGINFO ON CACHE BOOL "")
set(CLANG_PLUGIN_SUPPORT OFF CACHE BOOL "")
@ -23,19 +24,16 @@ if(APPLE)
endif()
set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "")
set(CMAKE_C_FLAGS_RELWITHDEBINFO "-O2 -gline-tables-only -DNDEBUG" CACHE STRING "")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -gline-tables-only -DNDEBUG" CACHE STRING "")
set(CMAKE_C_FLAGS_RELWITHDEBINFO "-O3 -gline-tables-only -DNDEBUG" CACHE STRING "")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O3 -gline-tables-only -DNDEBUG" CACHE STRING "")
set(LLVM_BUILTIN_TARGETS "x86_64-fuchsia;aarch64-fuchsia" CACHE STRING "")
set(LLVM_BUILTIN_TARGETS "default;x86_64-fuchsia;aarch64-fuchsia" CACHE STRING "")
foreach(target x86_64;aarch64)
set(BUILTINS_${target}-fuchsia_CMAKE_SYSROOT ${FUCHSIA_${target}_SYSROOT} CACHE PATH "")
set(BUILTINS_${target}-fuchsia_CMAKE_SYSTEM_NAME Fuchsia CACHE STRING "")
endforeach()
if(NOT APPLE)
list(APPEND LLVM_BUILTIN_TARGETS "default")
endif()
set(LLVM_RUNTIME_TARGETS "default;x86_64-fuchsia;aarch64-fuchsia" CACHE STRING "")
set(LLVM_RUNTIME_TARGETS "default;x86_64-fuchsia;aarch64-fuchsia;x86_64-fuchsia-asan:x86_64-fuchsia;aarch64-fuchsia-asan:aarch64-fuchsia" CACHE STRING "")
foreach(target x86_64;aarch64)
set(RUNTIMES_${target}-fuchsia_CMAKE_BUILD_WITH_INSTALL_RPATH ON CACHE BOOL "")
set(RUNTIMES_${target}-fuchsia_CMAKE_SYSROOT ${FUCHSIA_${target}_SYSROOT} CACHE PATH "")
@ -43,9 +41,19 @@ foreach(target x86_64;aarch64)
set(RUNTIMES_${target}-fuchsia_UNIX 1 CACHE BOOL "")
set(RUNTIMES_${target}-fuchsia_LLVM_ENABLE_LIBCXX ON CACHE BOOL "")
set(RUNTIMES_${target}-fuchsia_LIBUNWIND_USE_COMPILER_RT ON CACHE BOOL "")
set(RUNTIMES_${target}-fuchsia_LIBUNWIND_ENABLE_STATIC OFF CACHE BOOL "")
set(RUNTIMES_${target}-fuchsia_LIBCXXABI_USE_COMPILER_RT ON CACHE BOOL "")
set(RUNTIMES_${target}-fuchsia_LIBCXXABI_USE_LLVM_UNWINDER ON CACHE BOOL "")
set(RUNTIMES_${target}-fuchsia_LIBCXXABI_ENABLE_STATIC OFF CACHE BOOL "")
set(RUNTIMES_${target}-fuchsia_LIBCXX_USE_COMPILER_RT ON CACHE BOOL "")
set(RUNTIMES_${target}-fuchsia_LIBCXX_ABI_VERSION 2 CACHE STRING "")
set(RUNTIMES_${target}-fuchsia_LIBCXX_ENABLE_STATIC OFF CACHE BOOL "")
set(RUNTIMES_${target}-fuchsia_SANITIZER_USE_COMPILER_RT ON CACHE BOOL "")
set(RUNTIMES_${target}-fuchsia-asan_LLVM_USE_SANITIZER Address CACHE STRING "")
set(RUNTIMES_${target}-fuchsia-asan_LLVM_RUNTIMES_PREFIX "${target}-fuchsia/" CACHE STRING "")
set(RUNTIMES_${target}-fuchsia-asan_LLVM_RUNTIMES_LIBDIR_SUFFIX "/asan" CACHE STRING "")
set(RUNTIMES_${target}-fuchsia-asan_LIBCXX_INSTALL_HEADERS OFF CACHE BOOL "")
endforeach()
# Setup toolchain.
@ -59,6 +67,7 @@ set(LLVM_TOOLCHAIN_TOOLS
llvm-dsymutil
llvm-lib
llvm-nm
llvm-objcopy
llvm-objdump
llvm-profdata
llvm-ranlib
@ -67,6 +76,7 @@ set(LLVM_TOOLCHAIN_TOOLS
llvm-size
llvm-symbolizer
opt
sancov
CACHE STRING "")
set(LLVM_DISTRIBUTION_COMPONENTS
@ -77,6 +87,7 @@ set(LLVM_DISTRIBUTION_COMPONENTS
LTO
clang-format
clang-headers
clang-refactor
clang-tidy
clangd
builtins

View File

@ -8,8 +8,9 @@ set(LLVM_INCLUDE_EXAMPLES OFF CACHE BOOL "")
set(LLVM_INCLUDE_TESTS OFF CACHE BOOL "")
set(LLVM_INCLUDE_DOCS OFF CACHE BOOL "")
set(CLANG_INCLUDE_TESTS OFF CACHE BOOL "")
set(LLVM_ENABLE_ZLIB OFF CACHE BOOL "")
set(LLVM_ENABLE_BACKTRACES OFF CACHE BOOL "")
set(LLVM_ENABLE_TERMINFO OFF CACHE BOOL "")
set(LLVM_ENABLE_ZLIB OFF CACHE BOOL "")
set(CLANG_PLUGIN_SUPPORT OFF CACHE BOOL "")
set(CMAKE_BUILD_TYPE Release CACHE STRING "")

View File

@ -104,11 +104,9 @@ macro(add_clang_library name)
RUNTIME DESTINATION bin)
if (${ARG_SHARED} AND NOT CMAKE_CONFIGURATION_TYPES)
add_custom_target(install-${name}
DEPENDS ${name}
COMMAND "${CMAKE_COMMAND}"
-DCMAKE_INSTALL_COMPONENT=${name}
-P "${CMAKE_BINARY_DIR}/cmake_install.cmake")
add_llvm_install_targets(install-${name}
DEPENDS ${name}
COMPONENT ${name})
endif()
endif()
set_property(GLOBAL APPEND PROPERTY CLANG_EXPORTS ${name})
@ -147,11 +145,9 @@ macro(add_clang_tool name)
COMPONENT ${name})
if(NOT CMAKE_CONFIGURATION_TYPES)
add_custom_target(install-${name}
DEPENDS ${name}
COMMAND "${CMAKE_COMMAND}"
-DCMAKE_INSTALL_COMPONENT=${name}
-P "${CMAKE_BINARY_DIR}/cmake_install.cmake")
add_llvm_install_targets(install-${name}
DEPENDS ${name}
COMPONENT ${name})
endif()
set_property(GLOBAL APPEND PROPERTY CLANG_EXPORTS ${name})
endif()

View File

@ -11,3 +11,10 @@ set(CLANG_INCLUDE_DIRS "@CLANG_CONFIG_INCLUDE_DIRS@")
# Provide all our library targets to users.
include("@CLANG_CONFIG_EXPORTS_FILE@")
# By creating clang-tablegen-targets here, subprojects that depend on Clang's
# tablegen-generated headers can always depend on this target whether building
# in-tree with Clang or not.
if(NOT TARGET clang-tablegen-targets)
add_custom_target(clang-tablegen-targets)
endif()

View File

@ -0,0 +1,19 @@
set(PBM_PREFIX protobuf_mutator)
set(PBM_PATH ${CMAKE_CURRENT_BINARY_DIR}/${PBM_PREFIX}/src/${PBM_PREFIX})
set(PBM_LIB_PATH ${PBM_PATH}-build/src/libprotobuf-mutator.a)
set(PBM_FUZZ_LIB_PATH ${PBM_PATH}-build/src/libfuzzer/libprotobuf-mutator-libfuzzer.a)
ExternalProject_Add(${PBM_PREFIX}
PREFIX ${PBM_PREFIX}
GIT_REPOSITORY https://github.com/google/libprotobuf-mutator.git
GIT_TAG master
CMAKE_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
CMAKE_CACHE_ARGS -DCMAKE_C_COMPILER:FILEPATH=${CMAKE_C_COMPILER}
-DCMAKE_CXX_COMPILER:FILEPATH=${CMAKE_CXX_COMPILER}
BUILD_BYPRODUCTS ${PBM_LIB_PATH} ${PBM_FUZZ_LIB_PATH}
UPDATE_COMMAND ""
INSTALL_COMMAND ""
)
set(ProtobufMutator_INCLUDE_DIRS ${PBM_PATH})
set(ProtobufMutator_LIBRARIES ${PBM_FUZZ_LIB_PATH} ${PBM_LIB_PATH})

View File

@ -140,7 +140,8 @@ Memory leak detection
---------------------
For more information on leak detector in AddressSanitizer, see
:doc:`LeakSanitizer`. The leak detection is turned on by default on Linux;
:doc:`LeakSanitizer`. The leak detection is turned on by default on Linux,
and can be enabled using ``ASAN_OPTIONS=detect_leaks=1`` on OS X;
however, it is not yet supported on other platforms.
Issue Suppression

File diff suppressed because it is too large Load Diff

View File

@ -56,6 +56,16 @@ Pass <arg> to fatbinary invocation
Pass <arg> to the ptxas assembler
.. option:: -Xopenmp-target <arg>
Pass <arg> to the target offloading toolchain.
.. program:: clang1
.. option:: -Xopenmp-target=<arg> <arg2>
.. program:: clang
Pass <arg> to the specified target offloading toolchain. The triple that identifies the toolchain must be provided after the equals sign.
.. option:: -Z<arg>
.. option:: -a<arg>, --profile-blocks
@ -312,6 +322,10 @@ Disable standard #include directories for the C++ standard library
.. option:: -nostdlib, --no-standard-libraries
.. program:: clang1
.. option:: -nostdlib++
.. program:: clang
.. option:: -nostdlibinc
.. option:: -o<file>, --output <arg>, --output=<arg>
@ -510,10 +524,10 @@ Serialize compiler diagnostics to a file
.. option:: -shared, --shared
.. option:: -shared-libasan
.. option:: -shared-libgcc
.. option:: -shared-libsan, -shared-libasan
.. option:: -single\_module
.. option:: -specs=<arg>, --specs=<arg>
@ -522,6 +536,8 @@ Serialize compiler diagnostics to a file
.. option:: -static-libgcc
.. option:: -static-libsan
.. option:: -static-libstdc++
.. option:: -std-default=<arg>
@ -574,6 +590,8 @@ Verify the binary representation of debug output
.. option:: --version
Print version information
.. option:: -w, --no-warnings
Suppress all warnings
@ -688,6 +706,10 @@ Print source range spans in numeric form
Enables an experimental new pass manager in LLVM.
.. option:: -ffine-grained-bitfield-accesses, -fno-fine-grained-bitfield-accesses
Use separate accesses for bitfields with legal widths and alignments.
.. option:: -finline-functions, -fno-inline-functions
Inline suitable functions
@ -726,6 +748,10 @@ Path to blacklist file for sanitizers
Enable control flow integrity (CFI) checks for cross-DSO calls.
.. option:: -fsanitize-cfi-icall-generalize-pointers
Generalize pointers in CFI indirect call type signature checks
.. option:: -fsanitize-coverage=<arg1>,<arg2>..., -fno-sanitize-coverage=<arg1>,<arg2>...
Specify the type of coverage instrumentation for Sanitizers
@ -742,10 +768,12 @@ Enable origins tracking in MemorySanitizer
Enable origins tracking in MemorySanitizer
.. option:: -fsanitize-memory-use-after-dtor
.. option:: -fsanitize-memory-use-after-dtor, -fno-sanitize-memory-use-after-dtor
Enable use-after-destroy detection in MemorySanitizer
.. option:: -fsanitize-minimal-runtime, -fno-sanitize-minimal-runtime
.. option:: -fsanitize-recover, -fno-sanitize-recover
.. program:: clang1
@ -856,6 +884,10 @@ Use the last modification time of <file> as the build session timestamp
Time when the current build session started
.. option:: -fmodule-file=\[<name>=\]<file>
Specify the mapping of module name to precompiled module file, or load a module file if name is omitted.
.. option:: -fmodules-cache-path=<directory>
Specify the module cache path
@ -1243,8 +1275,16 @@ Print a template comparison tree for differing templates
Allow '$' in identifiers
.. option:: -fdouble-square-bracket-attributes, -fno-double-square-bracket-attributes
Enable '\[\[\]\]' attributes in all C and C++ language modes
.. option:: -fdwarf-directory-asm, -fno-dwarf-directory-asm
.. option:: -fdwarf-exceptions
Use DWARF style exceptions
.. option:: -felide-constructors, -fno-elide-constructors
.. option:: -feliminate-unused-debug-symbols, -fno-eliminate-unused-debug-symbols
@ -1321,10 +1361,18 @@ Implicitly search the file system for module map files.
.. option:: -finput-charset=<arg>
.. option:: -finstrument-function-entry-bare
Instrument function entry only, after inlining, without arguments to the instrumentation call
.. option:: -finstrument-functions
Generate calls to instrument function entry and exit
.. option:: -finstrument-functions-after-inlining
Like -finstrument-functions, but insert the calls after inlining
.. option:: -fintegrated-as, -fno-integrated-as, -integrated-as
Enable the integrated assembler
@ -1365,10 +1413,6 @@ Specify the maximum alignment to enforce on pointers lacking an explicit alignme
.. option:: -fmodule-file-deps, -fno-module-file-deps
.. option:: -fmodule-file=<file>
Load this precompiled module file
.. option:: -fmodule-map-file=<file>
Load this module map file
@ -1451,6 +1495,10 @@ Do not treat C++ operator name keywords as synonyms for operators
.. option:: -fno-working-directory
.. option:: -fnoopenmp-relocatable-target
Do not compile OpenMP target code as relocatable.
.. option:: -fnoopenmp-use-tls
.. option:: -fobjc-abi-version=<arg>
@ -1493,6 +1541,10 @@ Enable ARC-style weak references in Objective-C
.. option:: -fopenmp-dump-offload-linker-script
.. option:: -fopenmp-relocatable-target
OpenMP target code is compiled as relocatable using the -c flag. For OpenMP targets the code is relocatable by default.
.. option:: -fopenmp-use-tls
.. option:: -fopenmp-version=<arg>
@ -1533,6 +1585,10 @@ Override the default ABI to return all structs on the stack
.. option:: -fpie, -fno-pie
.. option:: -fplt, -fno-plt
Use the PLT to make function calls
.. option:: -fplugin=<dsopath>
Load the named plugin (dynamic shared object)
@ -1571,6 +1627,13 @@ Generate instrumented code to collect execution counts into <file> (overridden b
Use instrumentation data for profile-guided optimization
.. option:: -fprofile-sample-accurate, -fauto-profile-accurate, -fno-profile-sample-accurate
Specifies that the sample profile is accurate. If the sample
profile is accurate, callsites without profile samples are marked
as cold. Otherwise, treat callsites without profile samples as if
we have no profile
.. option:: -fprofile-sample-use, -fauto-profile, -fno-profile-sample-use
.. program:: clang1
@ -1623,6 +1686,10 @@ Turn on loop reroller
Generate a YAML optimization record file
.. option:: -fseh-exceptions
Use SEH style exceptions
.. option:: -fshort-enums, -fno-short-enums
Allocate to an enum type only as many bytes as it needs for the declared range of possible values
@ -1807,6 +1874,10 @@ Treat signed integer overflow as two's complement
Store string literals as writable data
.. option:: -fxray-always-emit-customevents, -fno-xray-always-emit-customevents
Determine whether to always emit \_\_xray\_customevent(...) calls even if the function it appears in is not always instrumented.
.. option:: -fxray-always-instrument=<arg>
Filename defining the whitelist for imbuing the 'always instrument' XRay attribute.
@ -1905,6 +1976,8 @@ Put objects of at most <size> bytes into small data section (MIPS / Hexagon)
Enable SVR4-style position-independent code (Mips only)
.. option:: -mabs=<arg>
.. option:: -malign-double
Align doubles to two words in structs (x86 only)
@ -1943,6 +2016,14 @@ Link stack frames through backchain on System Z
Set EABI type, e.g. 4, 5 or gnu (default depends on triple)
.. option:: -membedded-data, -mno-embedded-data
Place constants in the .rodata section instead of the .sdata section even if they meet the -G <size> threshold (MIPS)
.. option:: -mextern-sdata, -mno-extern-sdata
Assume that externally defined data is in the small data if it meets the -G <size> threshold (MIPS)
.. option:: -mfentry
Insert calls to fentry at function entry (x86 only)
@ -1965,6 +2046,10 @@ Use 64-bit floating point registers (MIPS only)
Enable merging of globals
.. option:: -mgpopt, -mno-gpopt
Use GP relative accesses for symbols known to be in a small data section (MIPS)
.. option:: -mhard-float
.. option:: -mhwdiv=<arg>, --mhwdiv <arg>, --mhwdiv=<arg>
@ -1989,6 +2074,10 @@ Use Intel MCU ABI
.. option:: -mldc1-sdc1, -mno-ldc1-sdc1
.. option:: -mlocal-sdata, -mno-local-sdata
Extend the -G behaviour to object local data (MIPS)
.. option:: -mlong-calls, -mno-long-calls
Generate branches with extended addressability, usually via indirect jumps.
@ -2031,6 +2120,10 @@ Omit frame pointer setup for leaf functions
Use copy relocations support for PIE builds
.. option:: -mprefer-vector-width=<arg>
Specifies preferred vector width for auto-vectorization. Defaults to 'none' which allows target specific decisions.
.. option:: -mqdsp6-compat
Enable hexagon-qdsp6 backward compatibility
@ -2113,6 +2206,10 @@ Generate code which only uses the general purpose registers (AArch64 only)
AMDGPU
------
.. option:: -mxnack, -mno-xnack
Enable XNACK (AMDGPU only)
ARM
---
.. option:: -ffixed-r9
@ -2143,10 +2240,18 @@ Disallow use of CRC instructions (ARM only)
Disallow generation of deprecated IT blocks for ARMv8. It is on by default for ARMv8 Thumb mode.
.. option:: -mtp=<arg>
Read thread pointer from coprocessor register (ARM only)
.. option:: -munaligned-access, -mno-unaligned-access
Allow memory accesses to be unaligned (AArch32/AArch64 only)
Hexagon
-------
.. option:: -mieee-rnd-near
Hexagon
-------
.. option:: -mhvx, -mno-hvx
@ -2157,7 +2262,15 @@ Enable Hexagon Vector eXtensions
Enable Hexagon Double Vector eXtensions
.. option:: -mieee-rnd-near
.. option:: -mhvx-length=<arg>
Set Hexagon Vector Length
.. program:: clang1
.. option:: -mhvx=<arg>
.. program:: clang
Enable Hexagon Vector eXtensions
PowerPC
-------
@ -2197,6 +2310,8 @@ PowerPC
WebAssembly
-----------
.. option:: -mnontrapping-fptoint, -mno-nontrapping-fptoint
.. option:: -msimd128, -mno-simd128
X86
@ -2255,6 +2370,8 @@ X86
.. option:: -mfxsr, -mno-fxsr
.. option:: -mibt, -mno-ibt
.. option:: -mlwp, -mno-lwp
.. option:: -mlzcnt, -mno-lzcnt
@ -2287,6 +2404,8 @@ X86
.. option:: -msha, -mno-sha
.. option:: -mshstk, -mno-shstk
.. option:: -msse, -mno-sse
.. option:: -msse2, -mno-sse2

View File

@ -11,7 +11,7 @@ Standalone Tool
===============
:program:`clang-format` is located in `clang/tools/clang-format` and can be used
to format C/C++/Obj-C code.
to format C/C++/Java/JavaScript/Objective-C/Protobuf code.
.. code-block:: console
@ -71,6 +71,7 @@ to format C/C++/Obj-C code.
Use -style="{key: value, ...}" to set specific
parameters, e.g.:
-style="{BasedOnStyle: llvm, IndentWidth: 8}"
-verbose - If set, shows the list of processed files
Generic Options:

View File

@ -271,15 +271,22 @@ the configuration (without a prefix: ``Auto``).
int b = 2; // comment b int b = 2; // comment about b
**AllowAllParametersOfDeclarationOnNextLine** (``bool``)
Allow putting all parameters of a function declaration onto
If the function declaration doesn't fit on a line,
allow putting all parameters of a function declaration onto
the next line even if ``BinPackParameters`` is ``false``.
.. code-block:: c++
true: false:
myFunction(foo, vs. myFunction(foo, bar, plop);
bar,
plop);
true:
void myFunction(
int a, int b, int c, int d, int e);
false:
void myFunction(int a,
int b,
int c,
int d,
int e);
**AllowShortBlocksOnASingleLine** (``bool``)
Allows contracting simple braced statements to a single line.
@ -533,6 +540,15 @@ the configuration (without a prefix: ``Auto``).
If ``BreakBeforeBraces`` is set to ``BS_Custom``, use this to specify how
each individual brace case should be handled. Otherwise, this is ignored.
.. code-block:: yaml
# Example of usage:
BreakBeforeBraces: Custom
BraceWrapping:
AfterEnum: true
AfterStruct: false
SplitEmptyFunction: false
Nested configuration flags:
@ -645,6 +661,21 @@ the configuration (without a prefix: ``Auto``).
int x;
}
* ``bool AfterExternBlock`` Wrap extern blocks.
.. code-block:: c++
true:
extern "C"
{
int foo();
}
false:
extern "C" {
int foo();
}
* ``bool BeforeCatch`` Wrap before ``catch``.
.. code-block:: c++
@ -679,7 +710,7 @@ the configuration (without a prefix: ``Auto``).
* ``bool IndentBraces`` Indent the wrapped braces themselves.
* ``bool SplitEmptyFunctionBody`` If ``false``, empty function body can be put on a single line.
* ``bool SplitEmptyFunction`` If ``false``, empty function body can be put on a single line.
This option is used only if the opening brace of the function has
already been wrapped, i.e. the `AfterFunction` brace wrapping mode is
set, and the function could/should not be put on a single line (as per
@ -691,6 +722,28 @@ the configuration (without a prefix: ``Auto``).
{} {
}
* ``bool SplitEmptyRecord`` If ``false``, empty record (e.g. class, struct or union) body
can be put on a single line. This option is used only if the opening
brace of the record has already been wrapped, i.e. the `AfterClass`
(for classes) brace wrapping mode is set.
.. code-block:: c++
class Foo vs. class Foo
{} {
}
* ``bool SplitEmptyNamespace`` If ``false``, empty namespace body can be put on a single line.
This option is used only if the opening brace of the namespace has
already been wrapped, i.e. the `AfterNamespace` brace wrapping mode is
set.
.. code-block:: c++
namespace Foo vs. namespace Foo
{} {
}
**BreakAfterJavaFieldAnnotations** (``bool``)
Break after each annotation on a field in Java files.
@ -941,9 +994,9 @@ the configuration (without a prefix: ``Auto``).
.. code-block:: c++
Constructor()
: initializer1(),
initializer2()
Constructor()
: initializer1(),
initializer2()
* ``BCIS_BeforeComma`` (in configuration: ``BeforeComma``)
Break constructor initializers before the colon and commas, and align
@ -951,18 +1004,18 @@ the configuration (without a prefix: ``Auto``).
.. code-block:: c++
Constructor()
: initializer1()
, initializer2()
Constructor()
: initializer1()
, initializer2()
* ``BCIS_AfterColon`` (in configuration: ``AfterColon``)
Break constructor initializers after the colon and commas.
.. code-block:: c++
Constructor() :
initializer1(),
initializer2()
Constructor() :
initializer1(),
initializer2()
@ -1120,6 +1173,45 @@ the configuration (without a prefix: ``Auto``).
For example: BOOST_FOREACH.
**IncludeBlocks** (``IncludeBlocksStyle``)
Dependent on the value, multiple ``#include`` blocks can be sorted
as one and divided based on category.
Possible values:
* ``IBS_Preserve`` (in configuration: ``Preserve``)
Sort each ``#include`` block separately.
.. code-block:: c++
#include "b.h" into #include "b.h"
#include <lib/main.h> #include "a.h"
#include "a.h" #include <lib/main.h>
* ``IBS_Merge`` (in configuration: ``Merge``)
Merge multiple ``#include`` blocks together and sort as one.
.. code-block:: c++
#include "b.h" into #include "a.h"
#include "b.h"
#include <lib/main.h> #include <lib/main.h>
#include "a.h"
* ``IBS_Regroup`` (in configuration: ``Regroup``)
Merge multiple ``#include`` blocks together and sort as one.
Then split into groups based on category priority. See ``IncludeCategories``.
.. code-block:: c++
#include "b.h" into #include "a.h"
#include "b.h"
#include <lib/main.h>
#include "a.h" #include <lib/main.h>
**IncludeCategories** (``std::vector<IncludeCategory>``)
Regular expressions denoting the different ``#include`` categories
used for ordering ``#includes``.
@ -1144,7 +1236,7 @@ the configuration (without a prefix: ``Auto``).
IncludeCategories:
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
Priority: 2
- Regex: '^(<|"(gtest|isl|json)/)'
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
Priority: 3
- Regex: '.*'
Priority: 1
@ -1179,6 +1271,35 @@ the configuration (without a prefix: ``Auto``).
plop(); plop();
} }
**IndentPPDirectives** (``PPDirectiveIndentStyle``)
The preprocessor directive indenting style to use.
Possible values:
* ``PPDIS_None`` (in configuration: ``None``)
Does not indent any directives.
.. code-block:: c++
#if FOO
#if BAR
#include <foo>
#endif
#endif
* ``PPDIS_AfterHash`` (in configuration: ``AfterHash``)
Indents directives after the hash.
.. code-block:: c++
#if FOO
# if BAR
# include <foo>
# endif
#endif
**IndentWidth** (``unsigned``)
The number of columns to use for indentation.
@ -1291,6 +1412,10 @@ the configuration (without a prefix: ``Auto``).
* ``LK_TableGen`` (in configuration: ``TableGen``)
Should be used for TableGen code.
* ``LK_TextProto`` (in configuration: ``TextProto``)
Should be used for Protocol Buffer messages in text format
(https://developers.google.com/protocol-buffers/).
**MacroBlockBegin** (``std::string``)
@ -1451,6 +1576,26 @@ the configuration (without a prefix: ``Auto``).
**RawStringFormats** (``std::vector<RawStringFormat>``)
Raw string delimiters denoting that the raw string contents are
code in a particular language and can be reformatted.
A raw string with a matching delimiter will be reformatted assuming the
specified language based on a predefined style given by 'BasedOnStyle'.
If 'BasedOnStyle' is not found, the formatting is based on llvm style.
To configure this in the .clang-format file, use:
.. code-block:: yaml
RawStringFormats:
- Delimiter: 'pb'
Language: TextProto
BasedOnStyle: llvm
- Delimiter: 'proto'
Language: TextProto
BasedOnStyle: google
**ReflowComments** (``bool``)
If ``true``, clang-format will attempt to re-flow comments.
@ -1478,6 +1623,14 @@ the configuration (without a prefix: ``Auto``).
**SortUsingDeclarations** (``bool``)
If ``true``, clang-format will sort using declarations.
The order of using declarations is defined as follows:
Split the strings by "::" and discard any initial empty strings. The last
element of each list is a non-namespace name; all others are namespace
names. Sort the lists of names lexicographically, where the sort order of
individual names is that all non-namespace names come before all namespace
names, and within those groups, names are in case-insensitive
lexicographic order.
.. code-block:: c++
false: true:

View File

@ -215,6 +215,23 @@ shared library boundaries are handled as if the callee was not compiled with
This scheme is currently only supported on the x86 and x86_64 architectures.
``-fsanitize-cfi-icall-generalize-pointers``
--------------------------------------------
Mismatched pointer types are a common cause of cfi-icall check failures.
Translation units compiled with the ``-fsanitize-cfi-icall-generalize-pointers``
flag relax pointer type checking for call sites in that translation unit,
applied across all functions compiled with ``-fsanitize=cfi-icall``.
Specifically, pointers in return and argument types are treated as equivalent as
long as the qualifiers for the type they point to match. For example, ``char*``
``char**`, and ``int*`` are considered equivalent types. However, ``char*`` and
``const char*`` are considered separate types.
``-fsanitize-cfi-icall-generalize-pointers`` is not compatible with
``-fsanitize-cfi-cross-dso``.
``-fsanitize=cfi-icall`` and ``-fsanitize=function``
----------------------------------------------------
@ -243,17 +260,25 @@ Blacklist
A :doc:`SanitizerSpecialCaseList` can be used to relax CFI checks for certain
source files, functions and types using the ``src``, ``fun`` and ``type``
entity types.
entity types. Specific CFI modes can be be specified using ``[section]``
headers.
.. code-block:: bash
# Suppress checking for code in a file.
# Suppress all CFI checking for code in a file.
src:bad_file.cpp
src:bad_header.h
# Ignore all functions with names containing MyFooBar.
fun:*MyFooBar*
# Ignore all types in the standard library.
type:std::*
# Disable only unrelated cast checks for this function
[cfi-unrelated-cast]
fun:*UnrelatedCast*
# Disable CFI call checks for this function without affecting cast checks
[cfi-vcall|cfi-nvcall|cfi-icall]
fun:*BadCall*
.. _cfi-cross-dso:

View File

@ -92,7 +92,7 @@ The compiler relies on co-operation from the linker in order to assemble
the bit vectors for the whole program. It currently does this using LLVM's
`type metadata`_ mechanism together with link-time optimization.
.. _address point: https://mentorembedded.github.io/cxx-abi/abi.html#vtable-general
.. _address point: http://itanium-cxx-abi.github.io/cxx-abi/abi.html#vtable-general
.. _type metadata: http://llvm.org/docs/TypeMetadata.html
.. _ByteArrayBuilder: http://llvm.org/docs/doxygen/html/structllvm_1_1ByteArrayBuilder.html

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,139 @@
=======================================================
Hardware-assisted AddressSanitizer Design Documentation
=======================================================
This page is a design document for
**hardware-assisted AddressSanitizer** (or **HWASAN**)
a tool similar to :doc:`AddressSanitizer`,
but based on partial hardware assistance.
The document is a draft, suggestions are welcome.
Introduction
============
:doc:`AddressSanitizer`
tags every 8 bytes of the application memory with a 1 byte tag (using *shadow memory*),
uses *redzones* to find buffer-overflows and
*quarantine* to find use-after-free.
The redzones, the quarantine, and, to a less extent, the shadow, are the
sources of AddressSanitizer's memory overhead.
See the `AddressSanitizer paper`_ for details.
AArch64 has the `Address Tagging`_, a hardware feature that allows
software to use 8 most significant bits of a 64-bit pointer as
a tag. HWASAN uses `Address Tagging`_
to implement a memory safety tool, similar to :doc:`AddressSanitizer`,
but with smaller memory overhead and slightly different (mostly better)
accuracy guarantees.
Algorithm
=========
* Every heap/stack/global memory object is forcibly aligned by `N` bytes
(`N` is e.g. 16 or 64)
* For every such object a random `K`-bit tag `T` is chosen (`K` is e.g. 4 or 8)
* The pointer to the object is tagged with `T`.
* The memory for the object is also tagged with `T`
(using a `N=>1` shadow memory)
* Every load and store is instrumented to read the memory tag and compare it
with the pointer tag, exception is raised on tag mismatch.
Instrumentation
===============
Memory Accesses
---------------
All memory accesses are prefixed with a call to a run-time function.
The function encodes the type and the size of access in its name;
it receives the address as a parameter, e.g. `__hwasan_load4(void *ptr)`;
it loads the memory tag, compares it with the
pointer tag, and executes `__builtin_trap` (or calls `__hwasan_error_load4(void *ptr)`) on mismatch.
It's possible to inline this callback too.
Heap
----
Tagging the heap memory/pointers is done by `malloc`.
This can be based on any malloc that forces all objects to be N-aligned.
Stack
-----
Special compiler instrumentation is required to align the local variables
by N, tag the memory and the pointers.
Stack instrumentation is expected to be a major source of overhead,
but could be optional.
TODO: details.
Globals
-------
TODO: details.
Error reporting
---------------
Errors are generated by `__builtin_trap` and are handled by a signal handler.
Attribute
---------
HWASAN uses its own LLVM IR Attribute `sanitize_hwaddress` and a matching
C function attribute. An alternative would be to re-use ASAN's attribute
`sanitize_address`. The reasons to use a separate attribute are:
* Users may need to disable ASAN but not HWASAN, or vise versa,
because the tools have different trade-offs and compatibility issues.
* LLVM (ideally) does not use flags to decide which pass is being used,
ASAN or HWASAN are being applied, based on the function attributes.
This does mean that users of HWASAN may need to add the new attribute
to the code that already uses the old attribute.
Comparison with AddressSanitizer
================================
HWASAN:
* Is less portable than :doc:`AddressSanitizer`
as it relies on hardware `Address Tagging`_ (AArch64).
Address Tagging can be emulated with compiler instrumentation,
but it will require the instrumentation to remove the tags before
any load or store, which is infeasible in any realistic environment
that contains non-instrumented code.
* May have compatibility problems if the target code uses higher
pointer bits for other purposes.
* May require changes in the OS kernels (e.g. Linux seems to dislike
tagged pointers passed from address space:
https://www.kernel.org/doc/Documentation/arm64/tagged-pointers.txt).
* **Does not require redzones to detect buffer overflows**,
but the buffer overflow detection is probabilistic, with roughly
`(2**K-1)/(2**K)` probability of catching a bug.
* **Does not require quarantine to detect heap-use-after-free,
or stack-use-after-return**.
The detection is similarly probabilistic.
The memory overhead of HWASAN is expected to be much smaller
than that of AddressSanitizer:
`1/N` extra memory for the shadow
and some overhead due to `N`-aligning all objects.
Related Work
============
* `SPARC ADI`_ implements a similar tool mostly in hardware.
* `Effective and Efficient Memory Protection Using Dynamic Tainting`_ discusses
similar approaches ("lock & key").
* `Watchdog`_ discussed a heavier, but still somewhat similar
"lock & key" approach.
* *TODO: add more "related work" links. Suggestions are welcome.*
.. _Watchdog: http://www.cis.upenn.edu/acg/papers/isca12_watchdog.pdf
.. _Effective and Efficient Memory Protection Using Dynamic Tainting: https://www.cc.gatech.edu/~orso/papers/clause.doudalis.orso.prvulovic.pdf
.. _SPARC ADI: https://lazytyped.blogspot.com/2017/09/getting-started-with-adi.html
.. _AddressSanitizer paper: https://www.usenix.org/system/files/conference/atc12/atc12-final39.pdf
.. _Address Tagging: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.den0024a/ch12s05s01.html

View File

@ -49,7 +49,7 @@ when the code is incorrect or dubious. In Clang, each diagnostic produced has
(at the minimum) a unique ID, an English translation associated with it, a
:ref:`SourceLocation <SourceLocation>` to "put the caret", and a severity
(e.g., ``WARNING`` or ``ERROR``). They can also optionally include a number of
arguments to the dianostic (which fill in "%0"'s in the string) as well as a
arguments to the diagnostic (which fill in "%0"'s in the string) as well as a
number of source ranges that related to the diagnostic.
In this section, we'll be giving examples produced by the Clang command line
@ -493,11 +493,11 @@ source code of the program. Important design points include:
In practice, the ``SourceLocation`` works together with the ``SourceManager``
class to encode two pieces of information about a location: its spelling
location and its instantiation location. For most tokens, these will be the
location and its expansion location. For most tokens, these will be the
same. However, for a macro expansion (or tokens that came from a ``_Pragma``
directive) these will describe the location of the characters corresponding to
the token and the location where the token was used (i.e., the macro
instantiation point or the location of the ``_Pragma`` itself).
expansion point or the location of the ``_Pragma`` itself).
The Clang front-end inherently depends on the location of a token being tracked
correctly. If it is ever incorrect, the front-end may get confused and die.
@ -795,7 +795,7 @@ preprocessor and notifies a client of the parsing progress.
Historically, the parser used to talk to an abstract ``Action`` interface that
had virtual methods for parse events, for example ``ActOnBinOp()``. When Clang
grew C++ support, the parser stopped supporting general ``Action`` clients --
it now always talks to the :ref:`Sema libray <Sema>`. However, the Parser
it now always talks to the :ref:`Sema library <Sema>`. However, the Parser
still accesses AST objects only through opaque types like ``ExprResult`` and
``StmtResult``. Only :ref:`Sema <Sema>` looks at the AST node contents of these
wrappers.
@ -1324,9 +1324,9 @@ range of iterators over declarations of "``f``".
function ``DeclContext::getPrimaryContext`` retrieves the "primary" context for
a given ``DeclContext`` instance, which is the ``DeclContext`` responsible for
maintaining the lookup table used for the semantics-centric view. Given a
DeclContext, one can obtain the set of declaration contexts that are semanticaly
connected to this declaration context, in source order, including this context
(which will be the only result, for non-namespace contexts) via
DeclContext, one can obtain the set of declaration contexts that are
semantically connected to this declaration context, in source order, including
this context (which will be the only result, for non-namespace contexts) via
``DeclContext::collectAllContexts``. Note that these functions are used
internally within the lookup and insertion methods of the ``DeclContext``, so
the vast majority of clients can ignore them.
@ -1514,7 +1514,7 @@ use an i-c-e where one is required, but accepting the code unless running with
Things get a little bit more tricky when it comes to compatibility with
real-world source code. Specifically, GCC has historically accepted a huge
superset of expressions as i-c-e's, and a lot of real world code depends on
this unfortuate accident of history (including, e.g., the glibc system
this unfortunate accident of history (including, e.g., the glibc system
headers). GCC accepts anything its "fold" optimizer is capable of reducing to
an integer constant, which means that the definition of what it accepts changes
as its optimizer does. One example is that GCC accepts things like "``case
@ -1540,7 +1540,7 @@ Implementation Approach
After trying several different approaches, we've finally converged on a design
(Note, at the time of this writing, not all of this has been implemented,
consider this a design goal!). Our basic approach is to define a single
recursive method evaluation method (``Expr::Evaluate``), which is implemented
recursive evaluation method (``Expr::Evaluate``), which is implemented
in ``AST/ExprConstant.cpp``. Given an expression with "scalar" type (integer,
fp, complex, or pointer) this method returns the following information:
@ -2037,7 +2037,7 @@ are similar.
* ``CodeGenFunction`` contains functions ``ConvertType`` and
``ConvertTypeForMem`` that convert Clang's types (``clang::Type*`` or
``clang::QualType``) to LLVM types. Use the former for values, and the
later for memory locations: test with the C++ "``bool``" type to check
latter for memory locations: test with the C++ "``bool``" type to check
this. If you find that you are having to use LLVM bitcasts to make the
subexpressions of your expression have the type that your expression
expects, STOP! Go fix semantic analysis and the AST so that you don't

View File

@ -91,3 +91,9 @@ 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.
Alternatives
============
For simple projects, Clang tools also recognize a compile_flags.txt file.
This should contain one flag per line. The same flags will be used to compile
any file.

View File

@ -139,6 +139,35 @@ and following ``__`` (double underscore) to avoid interference from a macro with
the same name. For instance, ``gnu::__const__`` can be used instead of
``gnu::const``.
``__has_c_attribute``
---------------------
This function-like macro takes a single argument that is the name of an
attribute exposed with the double square-bracket syntax in C mode. The argument
can either be a single identifier or a scoped identifier. If the attribute is
supported, a nonzero value is returned. If the attribute is not supported by the
current compilation target, this macro evaluates to 0. It can be used like this:
.. code-block:: c
#ifndef __has_c_attribute // Optional of course.
#define __has_c_attribute(x) 0 // Compatibility with non-clang compilers.
#endif
...
#if __has_c_attribute(fallthrough)
#define FALLTHROUGH [[fallthrough]]
#else
#define FALLTHROUGH
#endif
...
The attribute identifier (but not scope) can also be specified with a preceding
and following ``__`` (double underscore) to avoid interference from a macro with
the same name. For instance, ``gnu::__const__`` can be used instead of
``gnu::const``.
``__has_attribute``
-------------------
@ -436,6 +465,49 @@ const_cast no no no no
See also :ref:`langext-__builtin_shufflevector`, :ref:`langext-__builtin_convertvector`.
Half-Precision Floating Point
=============================
Clang supports two half-precision (16-bit) floating point types: ``__fp16`` and
``_Float16``. ``__fp16`` is defined in the ARM C Language Extensions (`ACLE
<http://infocenter.arm.com/help/topic/com.arm.doc.ihi0053d/IHI0053D_acle_2_1.pdf>`_)
and ``_Float16`` in ISO/IEC TS 18661-3:2015.
``__fp16`` is a storage and interchange format only. This means that values of
``__fp16`` promote to (at least) float when used in arithmetic operations.
There are two ``__fp16`` formats. Clang supports the IEEE 754-2008 format and
not the ARM alternative format.
ISO/IEC TS 18661-3:2015 defines C support for additional floating point types.
``_FloatN`` is defined as a binary floating type, where the N suffix denotes
the number of bits and is 16, 32, 64, or greater and equal to 128 and a
multiple of 32. Clang supports ``_Float16``. The difference from ``__fp16`` is
that arithmetic on ``_Float16`` is performed in half-precision, thus it is not
a storage-only format. ``_Float16`` is available as a source language type in
both C and C++ mode.
It is recommended that portable code use the ``_Float16`` type because
``__fp16`` is an ARM C-Language Extension (ACLE), whereas ``_Float16`` is
defined by the C standards committee, so using ``_Float16`` will not prevent
code from being ported to architectures other than Arm. Also, ``_Float16``
arithmetic and operations will directly map on half-precision instructions when
they are available (e.g. Armv8.2-A), avoiding conversions to/from
single-precision, and thus will result in more performant code. If
half-precision instructions are unavailable, values will be promoted to
single-precision, similar to the semantics of ``__fp16`` except that the
results will be stored in single-precision.
In an arithmetic operation where one operand is of ``__fp16`` type and the
other is of ``_Float16`` type, the ``_Float16`` type is first converted to
``__fp16`` type and then the operation is completed as if both operands were of
``__fp16`` type.
To define a ``_Float16`` literal, suffix ``f16`` can be appended to the compile-time
constant declaration. There is no default argument promotion for ``_Float16``; this
applies to the standard floating types only. As a consequence, for example, an
explicit cast is required for printing a ``_Float16`` value (there is no string
format specifier for ``_Float16``).
Messages on ``deprecated`` and ``unavailable`` Attributes
=========================================================
@ -1929,7 +2001,13 @@ provided, with values corresponding to the enumerators of C11's
``memory_order`` enumeration.
(Note that Clang additionally provides GCC-compatible ``__atomic_*``
builtins)
builtins and OpenCL 2.0 ``__opencl_atomic_*`` builtins. The OpenCL 2.0
atomic builtins are an explicit form of the corresponding OpenCL 2.0
builtin function, and are named with a ``__opencl_`` prefix. The macros
``__OPENCL_MEMORY_SCOPE_WORK_ITEM``, ``__OPENCL_MEMORY_SCOPE_WORK_GROUP``,
``__OPENCL_MEMORY_SCOPE_DEVICE``, ``__OPENCL_MEMORY_SCOPE_ALL_SVM_DEVICES``,
and ``__OPENCL_MEMORY_SCOPE_SUB_GROUP`` are provided, with values
corresponding to the enumerators of OpenCL's ``memory_scope`` enumeration.)
Low-level ARM exclusive memory builtins
---------------------------------------

View File

@ -17,7 +17,7 @@ detection phase.
Usage
=====
LeakSanitizer is only supported on x86\_64 Linux. In order to use it,
LeakSanitizer is supported on x86\_64 Linux and OS X. In order to use it,
simply build your program with :doc:`AddressSanitizer`:
.. code-block:: console
@ -30,7 +30,7 @@ simply build your program with :doc:`AddressSanitizer`:
p = 0; // The memory is leaked here.
return 0;
}
% clang -fsanitize=address -g memory-leak.c ; ./a.out
% clang -fsanitize=address -g memory-leak.c ; ASAN_OPTIONS=detect_leaks=1 ./a.out
==23646==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 7 byte(s) in 1 object(s) allocated from:
#0 0x4af01b in __interceptor_malloc /projects/compiler-rt/lib/asan/asan_malloc_linux.cc:52:3

View File

@ -346,6 +346,24 @@ Example matches Foo (Additions)
</pre></td></tr>
<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt;</td><td class="name" onclick="toggle('objcCategoryImplDecl0')"><a name="objcCategoryImplDecl0Anchor">objcCategoryImplDecl</a></td><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1ObjCCategoryImplDecl.html">ObjCCategoryImplDecl</a>&gt;...</td></tr>
<tr><td colspan="4" class="doc" id="objcCategoryImplDecl0"><pre>Matches Objective-C category definitions.
Example matches Foo (Additions)
@implementation Foo (Additions)
@end
</pre></td></tr>
<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt;</td><td class="name" onclick="toggle('objcImplementationDecl0')"><a name="objcImplementationDecl0Anchor">objcImplementationDecl</a></td><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1ObjCImplementationDecl.html">ObjCImplementationDecl</a>&gt;...</td></tr>
<tr><td colspan="4" class="doc" id="objcImplementationDecl0"><pre>Matches Objective-C implementation declarations.
Example matches Foo
@implementation Foo
@end
</pre></td></tr>
<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt;</td><td class="name" onclick="toggle('objcInterfaceDecl0')"><a name="objcInterfaceDecl0Anchor">objcInterfaceDecl</a></td><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1ObjCInterfaceDecl.html">ObjCInterfaceDecl</a>&gt;...</td></tr>
<tr><td colspan="4" class="doc" id="objcInterfaceDecl0"><pre>Matches Objective-C interface declarations.
@ -1207,6 +1225,24 @@ nullStmt()
</pre></td></tr>
<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('objcCatchStmt0')"><a name="objcCatchStmt0Anchor">objcCatchStmt</a></td><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1ObjCAtCatchStmt.html">ObjCAtCatchStmt</a>&gt;...</td></tr>
<tr><td colspan="4" class="doc" id="objcCatchStmt0"><pre>Matches Objective-C @catch statements.
Example matches @catch
@try {}
@catch (...) {}
</pre></td></tr>
<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('objcFinallyStmt0')"><a name="objcFinallyStmt0Anchor">objcFinallyStmt</a></td><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1ObjCAtFinallyStmt.html">ObjCAtFinallyStmt</a>&gt;...</td></tr>
<tr><td colspan="4" class="doc" id="objcFinallyStmt0"><pre>Matches Objective-C @finally statements.
Example matches @finally
@try {}
@finally {}
</pre></td></tr>
<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('objcMessageExpr0')"><a name="objcMessageExpr0Anchor">objcMessageExpr</a></td><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1ObjCMessageExpr.html">ObjCMessageExpr</a>&gt;...</td></tr>
<tr><td colspan="4" class="doc" id="objcMessageExpr0"><pre>Matches ObjectiveC Message invocation expressions.
@ -1218,6 +1254,23 @@ NSString's "alloc". This matcher should match both message sends.
</pre></td></tr>
<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('objcThrowStmt0')"><a name="objcThrowStmt0Anchor">objcThrowStmt</a></td><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1ObjCAtThrowStmt.html">ObjCAtThrowStmt</a>&gt;...</td></tr>
<tr><td colspan="4" class="doc" id="objcThrowStmt0"><pre>Matches Objective-C @throw statements.
Example matches @throw
@throw obj;
</pre></td></tr>
<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('objcTryStmt0')"><a name="objcTryStmt0Anchor">objcTryStmt</a></td><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1ObjCAtTryStmt.html">ObjCAtTryStmt</a>&gt;...</td></tr>
<tr><td colspan="4" class="doc" id="objcTryStmt0"><pre>Matches Objective-C @try statements.
Example matches @try
@try {}
@catch (...) {}
</pre></td></tr>
<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('opaqueValueExpr0')"><a name="opaqueValueExpr0Anchor">opaqueValueExpr</a></td><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1OpaqueValueExpr.html">OpaqueValueExpr</a>&gt;...</td></tr>
<tr><td colspan="4" class="doc" id="opaqueValueExpr0"><pre>Matches opaque value expressions. They are used as helpers
to reference another expressions and can be met
@ -1729,6 +1782,21 @@ substTemplateTypeParmType() matches the type of 't' but not '1'
</pre></td></tr>
<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>&gt;</td><td class="name" onclick="toggle('tagType0')"><a name="tagType0Anchor">tagType</a></td><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1TagType.html">TagType</a>&gt;...</td></tr>
<tr><td colspan="4" class="doc" id="tagType0"><pre>Matches tag types (record and enum types).
Given
enum E {};
class C {};
E e;
C c;
tagType() matches the type of the variable declarations of both e
and c.
</pre></td></tr>
<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>&gt;</td><td class="name" onclick="toggle('templateSpecializationType0')"><a name="templateSpecializationType0Anchor">templateSpecializationType</a></td><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>&gt;...</td></tr>
<tr><td colspan="4" class="doc" id="templateSpecializationType0"><pre>Matches template specialization types.
@ -2208,6 +2276,16 @@ Given
</pre></td></tr>
<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXNewExpr.html">CXXNewExpr</a>&gt;</td><td class="name" onclick="toggle('isArray0')"><a name="isArray0Anchor">isArray</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isArray0"><pre>Matches array new expressions.
Given:
MyClass *p1 = new MyClass[10];
cxxNewExpr(isArray())
matches the expression 'new MyClass[10]'.
</pre></td></tr>
<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXOperatorCallExpr.html">CXXOperatorCallExpr</a>&gt;</td><td class="name" onclick="toggle('hasOverloadedOperatorName1')"><a name="hasOverloadedOperatorName1Anchor">hasOverloadedOperatorName</a></td><td>StringRef Name</td></tr>
<tr><td colspan="4" class="doc" id="hasOverloadedOperatorName1"><pre>Matches overloaded operator names.
@ -2229,6 +2307,15 @@ Usable as: Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXOp
</pre></td></tr>
<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>&gt;</td><td class="name" onclick="toggle('hasDefinition0')"><a name="hasDefinition0Anchor">hasDefinition</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="hasDefinition0"><pre>Matches a class declaration that is defined.
Example matches x (matcher = cxxRecordDecl(hasDefinition()))
class x {};
class y;
</pre></td></tr>
<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>&gt;</td><td class="name" onclick="toggle('isDerivedFrom1')"><a name="isDerivedFrom1Anchor">isDerivedFrom</a></td><td>std::string BaseName</td></tr>
<tr><td colspan="4" class="doc" id="isDerivedFrom1"><pre>Overloaded method as shortcut for isDerivedFrom(hasName(...)).
</pre></td></tr>
@ -2678,8 +2765,8 @@ functionDecl(isDefaulted())
</pre></td></tr>
<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>&gt;</td><td class="name" onclick="toggle('isDefinition2')"><a name="isDefinition2Anchor">isDefinition</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isDefinition2"><pre>Matches if a declaration has a body attached.
<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>&gt;</td><td class="name" onclick="toggle('isDefinition3')"><a name="isDefinition3Anchor">isDefinition</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isDefinition3"><pre>Matches if a declaration has a body attached.
Example matches A, va, fa
class A {};
@ -2688,8 +2775,15 @@ Example matches A, va, fa
extern int vb; Doesn't match, as it doesn't define the variable.
void fa() {}
void fb(); Doesn't match, as it has no body.
@interface X
- (void)ma; Doesn't match, interface is declaration.
@end
@implementation X
- (void)ma {}
@end
Usable as: Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1TagDecl.html">TagDecl</a>&gt;, Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>&gt;, Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>&gt;
Usable as: Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1TagDecl.html">TagDecl</a>&gt;, Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>&gt;, Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>&gt;,
Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1ObjCMethodDecl.html">ObjCMethodDecl</a>&gt;
</pre></td></tr>
@ -2717,19 +2811,22 @@ functionDecl(isExplicitTemplateSpecialization())
Usable as: Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>&gt;, Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>&gt;, Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>&gt;
</pre></td></tr>
<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>&gt;</td><td class="name" onclick="toggle('isExternC0')"><a name="isExternC0Anchor">isExternC</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isExternC0"><pre>Matches extern "C" function declarations.
<tr><td colspan="4" class="doc" id="isExternC0"><pre>Matches extern "C" function or variable declarations.
Given:
extern "C" void f() {}
extern "C" { void g() {} }
void h() {}
extern "C" int x = 1;
extern "C" int y = 2;
int z = 3;
functionDecl(isExternC())
matches the declaration of f and g, but not the declaration h
matches the declaration of f and g, but not the declaration of h.
varDecl(isExternC())
matches the declaration of x and y, but not the declaration of z.
</pre></td></tr>
<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>&gt;</td><td class="name" onclick="toggle('isInline1')"><a name="isInline1Anchor">isInline</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isInline1"><pre>Matches function and namespace declarations that are marked with
the inline keyword.
@ -3083,6 +3180,37 @@ a substring matched by the given RegExp.
</pre></td></tr>
<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1ObjCMethodDecl.html">ObjCMethodDecl</a>&gt;</td><td class="name" onclick="toggle('isDefinition2')"><a name="isDefinition2Anchor">isDefinition</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isDefinition2"><pre>Matches if a declaration has a body attached.
Example matches A, va, fa
class A {};
class B; Doesn't match, as it has no body.
int va;
extern int vb; Doesn't match, as it doesn't define the variable.
void fa() {}
void fb(); Doesn't match, as it has no body.
@interface X
- (void)ma; Doesn't match, interface is declaration.
@end
@implementation X
- (void)ma {}
@end
Usable as: Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1TagDecl.html">TagDecl</a>&gt;, Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>&gt;, Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>&gt;,
Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1ObjCMethodDecl.html">ObjCMethodDecl</a>&gt;
</pre></td></tr>
<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1ParmVarDecl.html">ParmVarDecl</a>&gt;</td><td class="name" onclick="toggle('hasDefaultArgument0')"><a name="hasDefaultArgument0Anchor">hasDefaultArgument</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="hasDefaultArgument0"><pre>Matches a declaration that has default arguments.
Example matches y (matcher = parmVarDecl(hasDefaultArgument()))
void x(int val) {}
void y(int val = 0) {}
</pre></td></tr>
<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>&gt;</td><td class="name" onclick="toggle('asString0')"><a name="asString0Anchor">asString</a></td><td>std::string Name</td></tr>
<tr><td colspan="4" class="doc" id="asString0"><pre>Matches if the matched type is represented by the given string.
@ -3362,8 +3490,15 @@ Example matches A, va, fa
extern int vb; Doesn't match, as it doesn't define the variable.
void fa() {}
void fb(); Doesn't match, as it has no body.
@interface X
- (void)ma; Doesn't match, interface is declaration.
@end
@implementation X
- (void)ma {}
@end
Usable as: Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1TagDecl.html">TagDecl</a>&gt;, Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>&gt;, Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>&gt;
Usable as: Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1TagDecl.html">TagDecl</a>&gt;, Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>&gt;, Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>&gt;,
Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1ObjCMethodDecl.html">ObjCMethodDecl</a>&gt;
</pre></td></tr>
@ -3625,8 +3760,15 @@ Example matches A, va, fa
extern int vb; Doesn't match, as it doesn't define the variable.
void fa() {}
void fb(); Doesn't match, as it has no body.
@interface X
- (void)ma; Doesn't match, interface is declaration.
@end
@implementation X
- (void)ma {}
@end
Usable as: Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1TagDecl.html">TagDecl</a>&gt;, Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>&gt;, Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>&gt;
Usable as: Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1TagDecl.html">TagDecl</a>&gt;, Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>&gt;, Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>&gt;,
Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1ObjCMethodDecl.html">ObjCMethodDecl</a>&gt;
</pre></td></tr>
@ -3656,19 +3798,22 @@ functionDecl(isExplicitTemplateSpecialization())
Usable as: Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>&gt;, Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>&gt;, Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>&gt;
</pre></td></tr>
<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>&gt;</td><td class="name" onclick="toggle('isExternC1')"><a name="isExternC1Anchor">isExternC</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isExternC1"><pre>Matches extern "C" function declarations.
<tr><td colspan="4" class="doc" id="isExternC1"><pre>Matches extern "C" function or variable declarations.
Given:
extern "C" void f() {}
extern "C" { void g() {} }
void h() {}
extern "C" int x = 1;
extern "C" int y = 2;
int z = 3;
functionDecl(isExternC())
matches the declaration of f and g, but not the declaration h
matches the declaration of f and g, but not the declaration of h.
varDecl(isExternC())
matches the declaration of x and y, but not the declaration of z.
</pre></td></tr>
<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>&gt;</td><td class="name" onclick="toggle('isStaticStorageClass1')"><a name="isStaticStorageClass1Anchor">isStaticStorageClass</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isStaticStorageClass1"><pre>Matches variablefunction declarations that have "static" storage
class specifier ("static" keyword) written in the source.
@ -4350,6 +4495,16 @@ Example matches A() in the last line
</pre></td></tr>
<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXNewExpr.html">CXXNewExpr</a>&gt;</td><td class="name" onclick="toggle('hasArraySize0')"><a name="hasArraySize0Anchor">hasArraySize</a></td><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>&gt; InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="hasArraySize0"><pre>Matches array new expressions with a given array size.
Given:
MyClass *p1 = new MyClass[10];
cxxNewExpr(hasArraySize(intgerLiteral(equals(10))))
matches the expression 'new MyClass[10]'.
</pre></td></tr>
<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXNewExpr.html">CXXNewExpr</a>&gt;</td><td class="name" onclick="toggle('hasDeclaration12')"><a name="hasDeclaration12Anchor">hasDeclaration</a></td><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt; InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="hasDeclaration12"><pre>Matches a node if the declaration associated with that node
matches the given matcher.
@ -4546,6 +4701,18 @@ functionDecl(hasAnyTemplateArgument(refersToType(asString("int"))))
</pre></td></tr>
<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1ClassTemplateSpecializationDecl.html">ClassTemplateSpecializationDecl</a>&gt;</td><td class="name" onclick="toggle('hasSpecializedTemplate0')"><a name="hasSpecializedTemplate0Anchor">hasSpecializedTemplate</a></td><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1ClassTemplateDecl.html">ClassTemplateDecl</a>&gt; InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="hasSpecializedTemplate0"><pre>Matches the specialized template of a specialization declaration.
Given
tempalate&lt;typename T&gt; class A {};
typedef A&lt;int&gt; B;
classTemplateSpecializationDecl(hasSpecializedTemplate(classTemplateDecl()))
matches 'B' with classTemplateDecl() matching the class template
declaration of 'A'.
</pre></td></tr>
<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1ClassTemplateSpecializationDecl.html">ClassTemplateSpecializationDecl</a>&gt;</td><td class="name" onclick="toggle('hasTemplateArgument0')"><a name="hasTemplateArgument0Anchor">hasTemplateArgument</a></td><td>unsigned N, Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateArgument.html">TemplateArgument</a>&gt; InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="hasTemplateArgument0"><pre>Matches classTemplateSpecializations, templateSpecializationType and
functionDecl where the n'th TemplateArgument matches the given InnerMatcher.

View File

@ -213,8 +213,14 @@ Command-line parameters
``-fno-implicit-modules``
All modules used by the build must be specified with ``-fmodule-file``.
``-fmodule-file=<file>``
Load the given precompiled module file.
``-fmodule-file=[<name>=]<file>``
Specify the mapping of module names to precompiled module files. If the
name is omitted, then the module file is loaded whether actually required
or not. If the name is specified, then the mapping is treated as another
prebuilt module search mechanism (in addition to ``-fprebuilt-module-path``)
and the module is only loaded if required. Note that in this case the
specified file also overrides this module's paths that might be embedded
in other precompiled module files.
``-fprebuilt-module-path=<directory>``
Specify the path to the prebuilt modules. If specified, we will look for modules in this directory for a given top-level module name. We don't need a module map for loading prebuilt modules in this directory and the compiler will not try to rebuild these modules. This can be specified multiple times.
@ -317,11 +323,12 @@ Module map files use a simplified form of the C99 lexer, with the same rules for
.. parsed-literal::
``config_macros`` ``export`` ``private``
``config_macros`` ``export_as`` ``private``
``conflict`` ``framework`` ``requires``
``exclude`` ``header`` ``textual``
``explicit`` ``link`` ``umbrella``
``extern`` ``module`` ``use``
``export``
Module map file
---------------
@ -381,6 +388,7 @@ Modules can have a number of different kinds of members, each of which is descri
*umbrella-dir-declaration*
*submodule-declaration*
*export-declaration*
*export-as-declaration*
*use-declaration*
*link-declaration*
*config-macros-declaration*
@ -660,6 +668,30 @@ Note that, if ``Derived.h`` includes ``Base.h``, one can simply use a wildcard e
compatibility for programs that rely on transitive inclusion (i.e.,
all of them).
Re-export Declaration
~~~~~~~~~~~~~~~~~~~~~
An *export-as-declaration* specifies that the current module will have
its interface re-exported by the named module.
.. parsed-literal::
*export-as-declaration*:
``export_as`` *identifier*
The *export-as-declaration* names the module that the current
module will be re-exported through. Only top-level modules
can be re-exported, and any given module may only be re-exported
through a single module.
**Example:** In the following example, the module ``MyFrameworkCore``
will be re-exported via the module ``MyFramework``:
.. parsed-literal::
module MyFrameworkCore {
export_as MyFramework
}
Use declaration
~~~~~~~~~~~~~~~
A *use-declaration* specifies another module that the current top-level module
@ -945,4 +977,3 @@ PCHInternals_
.. [#] The preprocessing context in which the modules are parsed is actually dependent on the command-line options provided to the compiler, including the language dialect and any ``-D`` options. However, the compiled modules for different command-line options are kept distinct, and any preprocessor directives that occur within the translation unit are ignored. See the section on the `Configuration macros declaration`_ for more information.
.. _PCHInternals: PCHInternals.html

253
docs/RefactoringEngine.rst Normal file
View File

@ -0,0 +1,253 @@
==========================
Clang's refactoring engine
==========================
This document describes the design of Clang's refactoring engine and provides
a couple of examples that show how various primitives in the refactoring API
can be used to implement different refactoring actions. The :doc:`LibTooling`
library provides several other APIs that are used when developing a
refactoring action.
Refactoring engine can be used to implement local refactorings that are
initiated using a selection in an editor or an IDE. You can combine
:doc:`AST matchers<LibASTMatchers>` and the refactoring engine to implement
refactorings that don't lend themselves well to source selection and/or have to
query ASTs for some particular nodes.
We assume basic knowledge about the Clang AST. See the :doc:`Introduction
to the Clang AST <IntroductionToTheClangAST>` if you want to learn more
about how the AST is structured.
.. FIXME: create new refactoring action tutorial and link to the tutorial
Introduction
------------
Clang's refactoring engine defines a set refactoring actions that implement
a number of different source transformations. The ``clang-refactor``
command-line tool can be used to perform these refactorings. Certain
refactorings are also available in other clients like text editors and IDEs.
A refactoring action is a class that defines a list of related refactoring
operations (rules). These rules are grouped under a common umbrella - a single
``clang-refactor`` command. In addition to rules, the refactoring action
provides the action's command name and description to ``clang-refactor``.
Each action must implement the ``RefactoringAction`` interface. Here's an
outline of a ``local-rename`` action:
.. code-block:: c++
class LocalRename final : public RefactoringAction {
public:
StringRef getCommand() const override { return "local-rename"; }
StringRef getDescription() const override {
return "Finds and renames symbols in code with no indexer support";
}
RefactoringActionRules createActionRules() const override {
...
}
};
Refactoring Action Rules
------------------------
An individual refactoring action is responsible for creating the set of
grouped refactoring action rules that represent one refactoring operation.
Although the rules in one action may have a number of different implementations,
they should strive to produce a similar result. It should be easy for users to
identify which refactoring action produced the result regardless of which
refactoring action rule was used.
The distinction between actions and rules enables the creation of actions
that define a set of different rules that produce similar results. For example,
the "add missing switch cases" refactoring operation typically adds missing
cases to one switch at a time. However, it could be useful to have a
refactoring that works on all switches that operate on a particular enum, as
one could then automatically update all of them after adding a new enum
constant. To achieve that, we can create two different rules that will use one
``clang-refactor`` subcommand. The first rule will describe a local operation
that's initiated when the user selects a single switch. The second rule will
describe a global operation that works across translation units and is initiated
when the user provides the name of the enum to clang-refactor (or the user could
select the enum declaration instead). The clang-refactor tool will then analyze
the selection and other options passed to the refactoring action, and will pick
the most appropriate rule for the given selection and other options.
Rule Types
^^^^^^^^^^
Clang's refactoring engine supports several different refactoring rules:
- ``SourceChangeRefactoringRule`` produces source replacements that are applied
to the source files. Subclasses that choose to implement this rule have to
implement the ``createSourceReplacements`` member function. This type of
rule is typically used to implement local refactorings that transform the
source in one translation unit only.
- ``FindSymbolOccurrencesRefactoringRule`` produces a "partial" refactoring
result: a set of occurrences that refer to a particular symbol. This type
of rule is typically used to implement an interactive renaming action that
allows users to specify which occurrences should be renamed during the
refactoring. Subclasses that choose to implement this rule have to implement
the ``findSymbolOccurrences`` member function.
The following set of quick checks might help if you are unsure about the type
of rule you should use:
#. If you would like to transform the source in one translation unit and if
you don't need any cross-TU information, then the
``SourceChangeRefactoringRule`` should work for you.
#. If you would like to implement a rename-like operation with potential
interactive components, then ``FindSymbolOccurrencesRefactoringRule`` might
work for you.
How to Create a Rule
^^^^^^^^^^^^^^^^^^^^
Once you determine which type of rule is suitable for your needs you can
implement the refactoring by subclassing the rule and implementing its
interface. The subclass should have a constructor that takes the inputs that
are needed to perform the refactoring. For example, if you want to implement a
rule that simply deletes a selection, you should create a subclass of
``SourceChangeRefactoringRule`` with a constructor that accepts the selection
range:
.. code-block:: c++
class DeleteSelectedRange final : public SourceChangeRefactoringRule {
public:
DeleteSelection(SourceRange Selection) : Selection(Selection) {}
Expected<AtomicChanges>
createSourceReplacements(RefactoringRuleContext &Context) override {
AtomicChange Replacement(Context.getSources(), Selection.getBegin());
Replacement.replace(Context.getSource,
CharSourceRange::getCharRange(Selection), "");
return { Replacement };
}
private:
SourceRange Selection;
};
The rule's subclass can then be added to the list of refactoring action's
rules for a particular action using the ``createRefactoringActionRule``
function. For example, the class that's shown above can be added to the
list of action rules using the following code:
.. code-block:: c++
RefactoringActionRules Rules;
Rules.push_back(
createRefactoringActionRule<DeleteSelectedRange>(
SourceRangeSelectionRequirement())
);
The ``createRefactoringActionRule`` function takes in a list of refactoring
action rule requirement values. These values describe the initiation
requirements that have to be satisfied by the refactoring engine before the
provided action rule can be constructed and invoked. The next section
describes how these requirements are evaluated and lists all the possible
requirements that can be used to construct a refactoring action rule.
Refactoring Action Rule Requirements
------------------------------------
A refactoring action rule requirement is a value whose type derives from the
``RefactoringActionRuleRequirement`` class. The type must define an
``evaluate`` member function that returns a value of type ``Expected<...>``.
When a requirement value is used as an argument to
``createRefactoringActionRule``, that value is evaluated during the initiation
of the action rule. The evaluated result is then passed to the rule's
constructor unless the evaluation produced an error. For example, the
``DeleteSelectedRange`` sample rule that's defined in the previous section
will be evaluated using the following steps:
#. ``SourceRangeSelectionRequirement``'s ``evaluate`` member function will be
called first. It will return an ``Expected<SourceRange>``.
#. If the return value is an error the initiation will fail and the error
will be reported to the client. Note that the client may not report the
error to the user.
#. Otherwise the source range return value will be used to construct the
``DeleteSelectedRange`` rule. The rule will then be invoked as the initiation
succeeded (all requirements were evaluated successfully).
The same series of steps applies to any refactoring rule. Firstly, the engine
will evaluate all of the requirements. Then it will check if these requirements
are satisfied (they should not produce an error). Then it will construct the
rule and invoke it.
The separation of requirements, their evaluation and the invocation of the
refactoring action rule allows the refactoring clients to:
- Disable refactoring action rules whose requirements are not supported.
- Gather the set of options and define a command-line / visual interface
that allows users to input these options without ever invoking the
action.
Selection Requirements
^^^^^^^^^^^^^^^^^^^^^^
The refactoring rule requirements that require some form of source selection
are listed below:
- ``SourceRangeSelectionRequirement`` evaluates to a source range when the
action is invoked with some sort of selection. This requirement should be
satisfied when a refactoring is initiated in an editor, even when the user
has not selected anything (the range will contain the cursor's location in
that case).
.. FIXME: Future selection requirements
.. FIXME: Maybe mention custom selection requirements?
Other Requirements
^^^^^^^^^^^^^^^^^^
There are several other requirements types that can be used when creating
a refactoring rule:
- The ``RefactoringOptionsRequirement`` requirement is an abstract class that
should be subclassed by requirements working with options. The more
concrete ``OptionRequirement`` requirement is a simple implementation of the
aforementioned class that returns the value of the specified option when
it's evaluated. The next section talks more about refactoring options and
how they can be used when creating a rule.
Refactoring Options
-------------------
Refactoring options are values that affect a refactoring operation and are
specified either using command-line options or another client-specific
mechanism. Options should be created using a class that derives either from
the ``OptionalRequiredOption`` or ``RequiredRefactoringOption``. The following
example shows how one can created a required string option that corresponds to
the ``-new-name`` command-line option in clang-refactor:
.. code-block:: c++
class NewNameOption : public RequiredRefactoringOption<std::string> {
public:
StringRef getName() const override { return "new-name"; }
StringRef getDescription() const override {
return "The new name to change the symbol to";
}
};
The option that's shown in the example above can then be used to create
a requirement for a refactoring rule using a requirement like
``OptionRequirement``:
.. code-block:: c++
createRefactoringActionRule<RenameOccurrences>(
...,
OptionRequirement<NewNameOption>())
);
.. FIXME: Editor Bindings section

View File

@ -1,6 +1,6 @@
=========================
Clang 5.0.0 Release Notes
=========================
=======================================
Clang 6.0.0 (In-Progress) Release Notes
=======================================
.. contents::
:local:
@ -8,11 +8,17 @@ Clang 5.0.0 Release Notes
Written by the `LLVM Team <http://llvm.org/>`_
.. warning::
These are in-progress notes for the upcoming Clang 6 release.
Release notes for previous releases can be found on
`the Download Page <http://releases.llvm.org/download.html>`_.
Introduction
============
This document contains the release notes for the Clang C/C++/Objective-C
frontend, part of the LLVM Compiler Infrastructure, release 5.0.0. Here we
frontend, part of the LLVM Compiler Infrastructure, release 6.0.0. 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 `the LLVM
@ -24,7 +30,12 @@ For more information about Clang or LLVM, including information about the
latest release, please see the `Clang Web Site <http://clang.llvm.org>`_ or the
`LLVM Web Site <http://llvm.org>`_.
What's New in Clang 5.0.0?
Note that if you are reading this file from a Subversion checkout or the
main Clang web page, this document applies to the *next* release, not
the current one. To see the release notes for a specific release, please
see the `releases page <http://llvm.org/releases/>`_.
What's New in Clang 6.0.0?
==========================
Some of the major new features and improvements to Clang are listed
@ -35,48 +46,91 @@ sections with improvements to Clang's support for those languages.
Major New Features
------------------
C++ coroutines
^^^^^^^^^^^^^^
`C++ coroutines TS
<http://open-std.org/jtc1/sc22/wg21/docs/papers/2017/n4680.pdf>`_
implementation has landed. Use ``-fcoroutines-ts -stdlib=libc++`` to enable
coroutine support. Here is `an example
<https://wandbox.org/permlink/Dth1IO5q8Oe31ew2>`_ to get you started.
- ...
Improvements to Clang's diagnostics
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- ``-Wcast-qual`` was implemented for C++. C-style casts are now properly
diagnosed.
- ``-Wpragma-pack`` is a new warning that warns in the following cases:
- ``-Wunused-lambda-capture`` warns when a variable explicitly captured
by a lambda is not used in the body of the lambda.
- When a translation unit is missing terminating ``#pragma pack (pop)``
directives.
- ``-Wstrict-prototypes`` is a new warning that warns about non-prototype
function and block declarations and types in C and Objective-C.
- When leaving an included file that changes the current alignment value,
i.e. when the alignment before ``#include`` is different to the alignment
after ``#include``.
- ``-Wunguarded-availability`` is a new warning that warns about uses of new
APIs that were introduced in a system whose version is newer than the
deployment target version. A new Objective-C expression ``@available`` has
been introduced to perform system version checking at runtime. This warning
is off by default to prevent unexpected warnings in existing projects.
However, its less strict sibling ``-Wunguarded-availability-new`` is on by
default. It warns about unguarded uses of APIs only when they were introduced
in or after macOS 10.13, iOS 11, tvOS 11 or watchOS 4.
- ``-Wpragma-pack-suspicious-include`` (disabled by default) warns on an
``#include`` when the included file contains structures or unions affected by
a non-default alignment that has been specified using a ``#pragma pack``
directive prior to the ``#include``.
- The ``-Wdocumentation`` warning now allows the use of ``\param`` and
``\returns`` documentation directives in the documentation comments for
declarations with a function or a block pointer type.
- ``-Wobjc-messaging-id`` is a new, non-default warning that warns about
message sends to unqualified ``id`` in Objective-C. This warning is useful
for projects that would like to avoid any potential future compiler
errors/warnings, as the system frameworks might add a method with the same
selector which could make the message send to ``id`` ambiguous.
- The compiler no longer warns about unreachable ``__builtin_unreachable``
statements.
- ``-Wtautological-compare`` now warns when comparing an unsigned integer and 0
regardless of whether the constant is signed or unsigned."
- ``-Wtautological-compare`` now warns about comparing a signed integer and 0
when the signed integer is coerced to an unsigned type for the comparison.
``-Wsign-compare`` was adjusted not to warn in this case.
- ``-Wtautological-constant-compare`` is a new warning that warns on
tautological comparisons between integer variable of the type ``T`` and the
largest/smallest possible integer constant of that same type.
- For C code, ``-Wsign-compare``, ``-Wsign-conversion``,
``-Wtautological-constant-compare`` and
``-Wtautological-constant-out-of-range-compare`` were adjusted to use the
underlying datatype of ``enum``.
- ``-Wnull-pointer-arithmetic`` now warns about performing pointer arithmetic
on a null pointer. Such pointer arithmetic has an undefined behavior if the
offset is nonzero. It also now warns about arithmetic on a null pointer
treated as a cast from integer to pointer (GNU extension).
- ``-Wzero-as-null-pointer-constant`` was adjusted not to warn on null pointer
constants that originate from system macros, except ``NULL`` macro.
Non-comprehensive list of changes in this release
-------------------------------------------------
- Bitrig OS was merged back into OpenBSD, so Bitrig support has been
removed from Clang/LLVM.
- The default value of _MSC_VER was raised from 1800 to 1911, making it
compatible with the Visual Studio 2015 and 2017 C++ standard library headers.
Users should generally expect this to be regularly raised to match the most
recently released version of the Visual C++ compiler.
- clang now defaults to ``.init_array`` if no gcc installation can be found.
If a gcc installation is found, it still prefers ``.ctors`` if the found
gcc is older than 4.7.0.
- The new builtin preprocessor macros ``__is_target_arch``,
``__is_target_vendor``, ``__is_target_os``, and ``__is_target_environment``
can be used to to examine the individual components of the target triple.
New Compiler Flags
------------------
- ``--autocomplete`` was implemented to obtain a list of flags and its arguments.
This is used for shell autocompletion.
- --autocomplete was implemented to obtain a list of flags and its arguments. This is used for shell autocompletion.
- The ``-fdouble-square-bracket-attributes`` and corresponding
``-fno-double-square-bracket-attributes`` flags were added to enable or
disable [[]] attributes in any language mode. Currently, only a limited
number of attributes are supported outside of C++ mode. See the Clang
attribute documentation for more information about which attributes are
supported for each syntax.
- Added the ``-std=c17``, ``-std=gnu17``, and ``-std=iso9899:2017`` language
mode flags for compatibility with GCC. This enables support for the next
version of the C standard, expected to be published by ISO in 2018. The only
difference between the ``-std=c17`` and ``-std=c11`` language modes is the
value of the ``__STDC_VERSION__`` macro, as C17 is a bug fix release.
Deprecated Compiler Flags
-------------------------
@ -84,278 +138,194 @@ Deprecated Compiler Flags
The following options are deprecated and ignored. They will be removed in
future versions of Clang.
- ``-fslp-vectorize-aggressive`` used to enable the BB vectorizing pass. They have been superseeded
by the normal SLP vectorizer.
- ``-fno-slp-vectorize-aggressive`` used to be the default behavior of clang.
- ...
New Pragmas in Clang
-----------------------
- Clang now supports the ``clang attribute`` pragma that allows users to apply
an attribute to multiple declarations.
Clang now supports the ...
- ``pragma pack`` directives that are included in a precompiled header are now
applied correctly to the declarations in the compilation unit that includes
that precompiled header.
Attribute Changes in Clang
--------------------------
- The ``overloadable`` attribute now allows at most one function with a given
name to lack the ``overloadable`` attribute. This unmarked function will not
have its name mangled.
- The ``ms_abi`` attribute and the ``__builtin_ms_va_list`` types and builtins
are now supported on AArch64.
- Clang now supports the majority of its attributes under both the GNU-style
spelling (``__attribute((name))``) and the double square-bracket spelling
in the ``clang`` vendor namespace (``[[clang::name]]``). Attributes whose
syntax is specified by some other standard (such as CUDA and OpenCL
attributes) continue to follow their respective specification.
- Added the ``__has_c_attribute()`` builtin preprocessor macro which allows
users to dynamically detect whether a double square-bracket attribute is
supported in C mode. This attribute syntax can be enabled with the
``-fdouble-square-bracket-attributes`` flag.
- The presence of __attribute__((availability(...))) on a declaration no longer
implies default visibility for that declaration on macOS.
- ...
Windows Support
---------------
Clang's support for building native Windows programs ...
C Language Changes in Clang
---------------------------
- Added near complete support for implicit scalar to vector conversion, a GNU
C/C++ language extension. With this extension, the following code is
considered valid:
- ...
.. code-block:: c
...
typedef unsigned v4i32 __attribute__((vector_size(16)));
v4i32 foo(v4i32 a) {
// Here 5 is implicitly casted to an unsigned value and replicated into a
// vector with as many elements as 'a'.
return a + 5;
}
The implicit conversion of a scalar value to a vector value--in the context of
a vector expression--occurs when:
- The type of the vector is that of a ``__attribute__((vector_size(size)))``
vector, not an OpenCL ``__attribute__((ext_vector_type(size)))`` vector type.
- The scalar value can be casted to that of the vector element's type without
the loss of precision based on the type of the scalar and the type of the
vector's elements.
- For compile time constant values, the above rule is weakened to consider the
value of the scalar constant rather than the constant's type. However,
for compatibility with GCC, floating point constants with precise integral
representations are not implicitly converted to integer values.
Currently the basic integer and floating point types with the following
operators are supported: ``+``, ``/``, ``-``, ``*``, ``%``, ``>``, ``<``,
``>=``, ``<=``, ``==``, ``!=``, ``&``, ``|``, ``^`` and the corresponding
assignment operators where applicable.
C11 Feature Support
^^^^^^^^^^^^^^^^^^^
...
C++ Language Changes in Clang
-----------------------------
- We expect this to be the last Clang release that defaults to ``-std=gnu++98``
when using the GCC-compatible ``clang++`` driver. From Clang 6 onwards we
expect to use ``-std=gnu++14`` or a later standard by default, to match the
behavior of recent GCC releases. Users are encouraged to change their build
files to explicitly specify their desired C++ standard.
- Clang's default C++ dialect is now ``gnu++14`` instead of ``gnu++98``. This
means Clang will by default accept code using features from C++14 and
conforming GNU extensions. Projects incompatible with C++14 can add
``-std=gnu++98`` to their build settings to restore the previous behaviour.
- Support for the C++17 standard has been completed. This mode can be enabled
using ``-std=c++17`` (the old flag ``-std=c++1z`` is still supported for
compatibility).
C++1z Feature Support
^^^^^^^^^^^^^^^^^^^^^
- When targeting a platform that uses the Itanium C++ ABI, Clang implements a
`recent change to the ABI`__ that passes objects of class type indirectly if they
have a non-trivial move constructor. Previous versions of Clang only
considered the copy constructor, resulting in an ABI change in rare cases,
but GCC has already implemented this change for several releases.
This affects all targets other than Windows and PS4. You can opt out of this
ABI change with ``-fclang-abi-compat=4.0``.
- As mentioned in `C Language Changes in Clang`_, Clang's support for
implicit scalar to vector conversions also applies to C++. Additionally
the following operators are also supported: ``&&`` and ``||``.
.. __: https://github.com/itanium-cxx-abi/cxx-abi/commit/7099637aba11fed6bdad7ee65bf4fd3f97fbf076
...
Objective-C Language Changes in Clang
-------------------------------------
- Clang now guarantees that a ``readwrite`` property is synthesized when an
ambiguous property (i.e. a property that's declared in multiple protocols)
is synthesized. The ``-Wprotocol-property-synthesis-ambiguity`` warning that
warns about incompatible property types is now promoted to an error when
there's an ambiguity between ``readwrite`` and ``readonly`` properties.
- Clang now prohibits synthesis of ambiguous properties with incompatible
explicit property attributes. The following property attributes are
checked for differences: ``copy``, ``retain``/``strong``, ``atomic``,
``getter`` and ``setter``.
...
OpenCL C Language Changes in Clang
----------------------------------
Various bug fixes and improvements:
...
- Extended OpenCL-related Clang tests.
OpenMP Support in Clang
----------------------------------
- Improved diagnostics across several areas: scoped address space
qualified variables, function pointers, atomics, type rank for overloading,
block captures, ``reserve_id_t``.
...
- Several address space related fixes for constant address space function scope variables,
IR generation, mangling of ``generic`` and alloca (post-fix from general Clang
refactoring of address spaces).
Internal API Changes
--------------------
- Several improvements in extensions: fixed OpenCL version for ``cl_khr_mipmap_image``,
added missing ``cl_khr_3d_image_writes``.
These are major API changes that have happened since the 4.0.0 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.
- Improvements in ``enqueue_kernel``, especially the implementation of ``ndrange_t`` and blocks.
- ...
- OpenCL type related fixes: global samplers, the ``pipe_t`` size, internal type redefinition,
and type compatibility checking in ternary and other operations.
AST Matchers
------------
- The OpenCL header has been extended with missing extension guards, and direct mapping of ``as_type``
to ``__builtin_astype``.
The hasDeclaration matcher now works the same for Type and QualType and only
ever looks through one level of sugaring in a limited number of cases.
- Fixed ``kernel_arg_type_qual`` and OpenCL/SPIR version in metadata.
There are two main patterns affected by this:
- Added proper use of the kernel calling convention to various targets.
- qualType(hasDeclaration(recordDecl(...))): previously, we would look through
sugar like TypedefType to get at the underlying recordDecl; now, we need
to explicitly remove the sugaring:
qualType(hasUnqualifiedDesugaredType(hasDeclaration(recordDecl(...))))
The following new functionalities have been added:
- hasType(recordDecl(...)): hasType internally uses hasDeclaration; previously,
this matcher used to match for example TypedefTypes of the RecordType, but
after the change they don't; to fix, use:
- Added documentation on OpenCL to Clang user manual.
::
hasType(hasUnqualifiedDesugaredType(
recordType(hasDeclaration(recordDecl(...)))))
- Extended Clang builtins with required ``cl_khr_subgroups`` support.
- Add ``intel_reqd_sub_group_size`` attribute support.
- Added OpenCL types to ``CIndex``.
- templateSpecializationType(hasDeclaration(classTemplateDecl(...))):
previously, we would directly match the underlying ClassTemplateDecl;
now, we can explicitly match the ClassTemplateSpecializationDecl, but that
requires to explicitly get the ClassTemplateDecl:
::
templateSpecializationType(hasDeclaration(
classTemplateSpecializationDecl(
hasSpecializedTemplate(classTemplateDecl(...)))))
clang-format
------------
* Option **BreakBeforeInheritanceComma** added to break before ``:`` and ``,`` in case of
multiple inheritance in a class declaration. Enabled by default in the Mozilla coding style.
* Option *IndentPPDirectives* added to indent preprocessor directives on
conditionals.
+---------------------+----------------------------------------+
| true | false |
+=====================+========================================+
| .. code-block:: c++ | .. code-block:: c++ |
| | |
| class MyClass | class MyClass : public X, public Y { |
| : public X | }; |
| , public Y { | |
| }; | |
+---------------------+----------------------------------------+
+----------------------+----------------------+
| Before | After |
+======================+======================+
| .. code-block:: c++ | .. code-block:: c++ |
| | |
| #if FOO | #if FOO |
| #if BAR | # if BAR |
| #include <foo> | # include <foo> |
| #endif | # endif |
| #endif | #endif |
+----------------------+----------------------+
* Align block comment decorations.
* Option -verbose added to the command line.
Shows the list of processed files.
+----------------------+---------------------+
| Before | After |
+======================+=====================+
| .. code-block:: c++ | .. code-block:: c++ |
| | |
| /* line 1 | /* line 1 |
| * line 2 | * line 2 |
| */ | */ |
+----------------------+---------------------+
* Option *IncludeBlocks* added to merge and regroup multiple ``#include`` blocks during sorting.
* The :doc:`ClangFormatStyleOptions` documentation provides detailed examples for most options.
* Namespace end comments are now added or updated automatically.
+---------------------+---------------------+
| Before | After |
+=====================+=====================+
| .. code-block:: c++ | .. code-block:: c++ |
| | |
| namespace A { | namespace A { |
| int i; | int i; |
| int j; | int j; |
| } | } // namespace A |
+---------------------+---------------------+
* Comment reflow support added. Overly long comment lines will now be reflown with the rest of
the paragraph instead of just broken. Option **ReflowComments** added and enabled by default.
+-------------------------+-------------------------+-------------------------+
| Before (Preserve) | Merge | Regroup |
+=========================+=========================+=========================+
| .. code-block:: c++ | .. code-block:: c++ | .. code-block:: c++ |
| | | |
| #include "b.h" | #include "a.h" | #include "a.h" |
| | #include "b.h" | #include "b.h" |
| #include "a.b" | #include <lib/main.h> | |
| #include <lib/main.h> | | #include <lib/main.h> |
+-------------------------+-------------------------+-------------------------+
libclang
--------
- Libclang now provides code-completion results for more C++ constructs
and keywords. The following keywords/identifiers are now included in the
code-completion results: ``static_assert``, ``alignas``, ``constexpr``,
``final``, ``noexcept``, ``override`` and ``thread_local``.
...
- Libclang now provides code-completion results for members from dependent
classes. For example:
.. code-block:: c++
template<typename T>
void appendValue(std::vector<T> &dest, const T &value) {
dest. // Relevant completion results are now shown after '.'
}
Note that code-completion results are still not provided when the member
expression includes a dependent base expression. For example:
.. code-block:: c++
template<typename T>
void appendValue(std::vector<std::vector<T>> &dest, const T &value) {
dest.at(0). // Libclang fails to provide completion results after '.'
}
Static Analyzer
---------------
- The static analyzer now supports using the
`z3 theorem prover <https://github.com/z3prover/z3>`_ from Microsoft Research
as an external constraint solver. This allows reasoning over more complex
queries, but performance is ~15x slower than the default range-based
constraint solver. To enable the z3 solver backend, clang must be built with
the ``CLANG_ANALYZER_BUILD_Z3=ON`` option, and the
``-Xanalyzer -analyzer-constraints=z3`` arguments passed at runtime.
- Static Analyzer can now properly detect and diagnose unary pre-/post-
increment/decrement on an uninitialized value.
...
Undefined Behavior Sanitizer (UBSan)
------------------------------------
- The Undefined Behavior Sanitizer has a new check for pointer overflow. This
check is on by default. The flag to control this functionality is
``-fsanitize=pointer-overflow``.
* A minimal runtime is now available. It is suitable for use in production
environments, and has a small attack surface. It only provides very basic
issue logging and deduplication, and does not support ``-fsanitize=vptr``
checking.
Pointer overflow is an indicator of undefined behavior: when a pointer
indexing expression wraps around the address space, or produces other
unexpected results, its result may not point to a valid object.
Core Analysis Improvements
==========================
- UBSan has several new checks which detect violations of nullability
annotations. These checks are off by default. The flag to control this group
of checks is ``-fsanitize=nullability``. The checks can be individially enabled
by ``-fsanitize=nullability-arg`` (which checks calls),
``-fsanitize=nullability-assign`` (which checks assignments), and
``-fsanitize=nullability-return`` (which checks return statements).
- ...
- UBSan can now detect invalid loads from bitfields and from ObjC BOOLs.
- UBSan can now avoid emitting unnecessary type checks in C++ class methods and
in several other cases where the result is known at compile-time. UBSan can
also avoid emitting unnecessary overflow checks in arithmetic expressions
with promoted integer operands.
New Issues Found
================
- ...
Python Binding Changes
----------------------
Python bindings now support both Python 2 and Python 3.
The following methods have been added:
- ``is_scoped_enum`` has been added to ``Cursor``.
- ``exception_specification_kind`` has been added to ``Cursor``.
- ``get_address_space`` has been added to ``Type``.
- ``get_typedef_name`` has been added to ``Type``.
- ``get_exception_specification_kind`` has been added to ``Type``.
- ...
Significant Known Problems
==========================
Additional Information
======================

View File

@ -119,6 +119,53 @@ Example:
guard: 0x71bcdc 4 PC 0x4ecdc7 in main trace-pc-guard-example.cc:4:17
guard: 0x71bcd0 1 PC 0x4ecd20 in foo() trace-pc-guard-example.cc:2:14
Inline 8bit-counters
====================
**Experimental, may change or disappear in future**
With ``-fsanitize-coverage=inline-8bit-counters`` the compiler will insert
inline counter increments on every edge.
This is similar to ``-fsanitize-coverage=trace-pc-guard`` but instead of a
callback the instrumentation simply increments a counter.
Users need to implement a single function to capture the counters at startup.
.. code-block:: c++
extern "C"
void __sanitizer_cov_8bit_counters_init(char *start, char *end) {
// [start,end) is the array of 8-bit counters created for the current DSO.
// Capture this array in order to read/modify the counters.
}
PC-Table
========
**Experimental, may change or disappear in future**
With ``-fsanitize-coverage=pc-table`` the compiler will create a table of
instrumented PCs. Requires either ``-fsanitize-coverage=inline-8bit-counters`` or
``-fsanitize-coverage=trace-pc-guard``.
Users need to implement a single function to capture the PC table at startup:
.. code-block:: c++
extern "C"
void __sanitizer_cov_pcs_init(const uintptr_t *pcs_beg,
const uintptr_t *pcs_end) {
// [pcs_beg,pcs_end) is the array of ptr-sized integers representing
// pairs [PC,PCFlags] for every instrumented block in the current DSO.
// Capture this array in order to read the PCs and their Flags.
// The number of PCs and PCFlags for a given DSO is the same as the number
// of 8-bit counters (-fsanitize-coverage=inline-8bit-counters) or
// trace_pc_guard callbacks (-fsanitize-coverage=trace-pc-guard)
// A PCFlags describes the basic block:
// * bit0: 1 if the block is the function entry block, 0 otherwise.
}
Tracing PCs
===========
@ -131,7 +178,6 @@ by the user.
This mechanism is used for fuzzing the Linux kernel
(https://github.com/google/syzkaller).
Instrumentation points
======================
Sanitizer Coverage offers different levels of instrumentation.
@ -211,6 +257,14 @@ the `LLVM GEP instructions <http://llvm.org/docs/GetElementPtr.html>`_
void __sanitizer_cov_trace_cmp4(uint32_t Arg1, uint32_t Arg2);
void __sanitizer_cov_trace_cmp8(uint64_t Arg1, uint64_t Arg2);
// Called before a comparison instruction if exactly one of the arguments is constant.
// Arg1 and Arg2 are arguments of the comparison, Arg1 is a compile-time constant.
// These callbacks are emitted by -fsanitize-coverage=trace-cmp since 2017-08-11
void __sanitizer_cov_trace_const_cmp1(uint8_t Arg1, uint8_t Arg2);
void __sanitizer_cov_trace_const_cmp2(uint16_t Arg1, uint16_t Arg2);
void __sanitizer_cov_trace_const_cmp4(uint32_t Arg1, uint32_t Arg2);
void __sanitizer_cov_trace_const_cmp8(uint64_t Arg1, uint64_t Arg2);
// Called before a switch statement.
// Val is the switch operand.
// Cases[0] is the number of case constants.
@ -227,9 +281,6 @@ the `LLVM GEP instructions <http://llvm.org/docs/GetElementPtr.html>`_
// for every non-constant array index.
void __sanitizer_cov_trace_gep(uintptr_t Idx);
This interface is a subject to change.
Default implementation
======================

View File

@ -51,14 +51,23 @@ Example
Format
======
Each line contains an entity type, followed by a colon and a regular
expression, specifying the names of the entities, optionally followed by
an equals sign and a tool-specific category. Empty lines and lines starting
with "#" are ignored. The meanining of ``*`` in regular expression for entity
names is different - it is treated as in shell wildcarding. Two generic
entity types are ``src`` and ``fun``, which allow user to add, respectively,
source files and functions to special case list. Some sanitizer tools may
introduce custom entity types - refer to tool-specific docs.
Blacklists consist of entries, optionally grouped into sections. Empty lines and
lines starting with "#" are ignored.
Section names are regular expressions written in square brackets that denote
which sanitizer the following entries apply to. For example, ``[address]``
specifies AddressSanitizer while ``[cfi-vcall|cfi-icall]`` specifies Control
Flow Integrity virtual and indirect call checking. Entries without a section
will be placed under the ``[*]`` section applying to all enabled sanitizers.
Entries contain an entity type, followed by a colon and a regular expression,
specifying the names of the entities, optionally followed by an equals sign and
a tool-specific category, e.g. ``fun:*ExampleFunc=example_category``. The
meaning of ``*`` in regular expression for entity names is different - it is
treated as in shell wildcarding. Two generic entity types are ``src`` and
``fun``, which allow users to specify source files and functions, respectively.
Some sanitizer tools may introduce custom entity types and categories - refer to
tool-specific docs.
.. code-block:: bash
@ -77,3 +86,10 @@ introduce custom entity types - refer to tool-specific docs.
fun:*BadFunction*
# Specific sanitizer tools may introduce categories.
src:/special/path/*=special_sources
# Sections can be used to limit blacklist entries to specific sanitizers
[address]
fun:*BadASanFunc*
# Section names are regular expressions
[cfi-vcall|cfi-icall]
fun:*BadCfiCall
# Entries without sections are placed into [*] and apply to all sanitizers

View File

@ -63,7 +63,7 @@ ThinLTO is currently supported for the following linkers:
- **ld64**:
Starting with `Xcode 8 <https://developer.apple.com/xcode/>`_.
- **lld**:
Starting with r284050 (ELF only).
Starting with r284050 for ELF, r298942 for COFF.
Usage
=====
@ -78,6 +78,13 @@ To utilize ThinLTO, simply add the -flto=thin option to compile and link. E.g.
% clang -flto=thin -O2 file1.c file2.c -c
% clang -flto=thin -O2 file1.o file2.o -o a.out
When using lld-link, the -flto option need only be added to the compile step:
.. code-block:: console
% clang-cl -flto=thin -O2 -c file1.c file2.c
% lld-link /out:a.exe file1.obj file2.obj
As mentioned earlier, by default the linkers will launch the ThinLTO backend
threads in parallel, passing the resulting native object files back to the
linker for the final native link. As such, the usage model the same as
@ -111,6 +118,8 @@ be reduced to ``N`` via:
``-Wl,-mllvm,-threads=N``
- lld:
``-Wl,--thinlto-jobs=N``
- lld-link:
``/opt:lldltojobs=N``
Incremental
-----------
@ -119,23 +128,29 @@ Incremental
ThinLTO supports fast incremental builds through the use of a cache,
which currently must be enabled through a linker option.
- gold (as of LLVM r279883):
- gold (as of LLVM 4.0):
``-Wl,-plugin-opt,cache-dir=/path/to/cache``
- ld64 (support in clang 3.9 and Xcode 8):
``-Wl,-cache_path_lto,/path/to/cache``
- lld (as of LLVM r296702):
- ELF lld (as of LLVM 5.0):
``-Wl,--thinlto-cache-dir=/path/to/cache``
- COFF lld-link (as of LLVM 6.0):
``/lldltocache:/path/to/cache``
Cache Pruning
-------------
To help keep the size of the cache under control, ThinLTO supports cache
pruning. Cache pruning is supported with ld64 and ELF lld, but currently only
ELF lld allows you to control the policy with a policy string. The cache
policy must be specified with a linker option.
pruning. Cache pruning is supported with gold, ld64 and ELF and COFF lld, but
currently only gold, ELF and COFF lld allow you to control the policy with a
policy string. The cache policy must be specified with a linker option.
- ELF lld (as of LLVM r298036):
- gold (as of LLVM 6.0):
``-Wl,-plugin-opt,cache-policy=POLICY``
- ELF lld (as of LLVM 5.0):
``-Wl,--thinlto-cache-policy,POLICY``
- COFF lld-link (as of LLVM 6.0):
``/lldltocachepolicy:POLICY``
A policy string is a series of key-value pairs separated by ``:`` characters.
Possible key-value pairs are:
@ -158,6 +173,10 @@ Possible key-value pairs are:
``cache_size_bytes=1g`` on its own will cause both the 1GB and default 75%
policies to be applied unless the default ``cache_size`` is overridden.
- ``cache_size_files=X``:
Set the maximum number of files in the cache directory. Set to 0 to indicate
no limit. The default is 1000000 files.
- ``prune_after=Xs``, ``prune_after=Xm``, ``prune_after=Xh``: Sets the
expiration time for cache files to ``X`` seconds (or minutes, hours
respectively). When a file hasn't been accessed for ``prune_after`` seconds,
@ -183,13 +202,20 @@ To bootstrap clang/LLVM with ThinLTO, follow these steps:
when configuring the bootstrap compiler build:
* ``-DLLVM_ENABLE_LTO=Thin``
* ``-DLLVM_PARALLEL_LINK_JOBS=1``
(since the ThinLTO link invokes parallel backend jobs)
* ``-DCMAKE_C_COMPILER=/path/to/host/clang``
* ``-DCMAKE_CXX_COMPILER=/path/to/host/clang++``
* ``-DCMAKE_RANLIB=/path/to/host/llvm-ranlib``
* ``-DCMAKE_AR=/path/to/host/llvm-ar``
Or, on Windows:
* ``-DLLVM_ENABLE_LTO=Thin``
* ``-DCMAKE_C_COMPILER=/path/to/host/clang-cl.exe``
* ``-DCMAKE_CXX_COMPILER=/path/to/host/clang-cl.exe``
* ``-DCMAKE_LINKER=/path/to/host/lld-link.exe``
* ``-DCMAKE_RANLIB=/path/to/host/llvm-ranlib.exe``
* ``-DCMAKE_AR=/path/to/host/llvm-ar.exe``
#. To use additional linker arguments for controlling the backend
parallelism_ or enabling incremental_ builds of the bootstrap compiler,
after configuring the build, modify the resulting CMakeCache.txt file in the

View File

@ -222,7 +222,7 @@ Unwind library
The unwind library provides a family of ``_Unwind_*`` functions implementing
the language-neutral stack unwinding portion of the Itanium C++ ABI
(`Level I <http://mentorembedded.github.io/cxx-abi/abi-eh.html#base-abi>`_).
(`Level I <http://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html#base-abi>`_).
It is a dependency of the C++ ABI library, and sometimes is a dependency
of other runtimes.
@ -288,9 +288,9 @@ C++ ABI library
The C++ ABI library provides an implementation of the library portion of
the Itanium C++ ABI, covering both the
`support functionality in the main Itanium C++ ABI document
<http://mentorembedded.github.io/cxx-abi/abi.html>`_ and
<http://itanium-cxx-abi.github.io/cxx-abi/abi.html>`_ and
`Level II of the exception handling support
<http://mentorembedded.github.io/cxx-abi/abi-eh.html#cxx-abi>`_.
<http://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html#cxx-abi>`_.
References to the functions and objects in this library are implicitly
generated by Clang when compiling C++ code.

View File

@ -75,6 +75,7 @@ Available checks are:
of a misaligned reference.
- ``-fsanitize=bool``: Load of a ``bool`` value which is neither
``true`` nor ``false``.
- ``-fsanitize=builtin``: Passing invalid values to compiler builtins.
- ``-fsanitize=bounds``: Out of bounds array indexing, in cases
where the array bound can be statically determined.
- ``-fsanitize=enum``: Load of a value of an enumerated type which
@ -86,7 +87,8 @@ Available checks are:
- ``-fsanitize=float-divide-by-zero``: Floating point division by
zero.
- ``-fsanitize=function``: Indirect call of a function through a
function pointer of the wrong type (Linux, C++ and x86/x86_64 only).
function pointer of the wrong type (Darwin/Linux, C++ and x86/x86_64
only).
- ``-fsanitize=integer-divide-by-zero``: Integer division by zero.
- ``-fsanitize=nonnull-attribute``: Passing null pointer as a function
parameter which is declared to never be null.
@ -130,11 +132,11 @@ Available checks are:
it is often unintentional, so UBSan offers to catch it.
- ``-fsanitize=vla-bound``: A variable-length array whose bound
does not evaluate to a positive value.
- ``-fsanitize=vptr``: Use of an object whose vptr indicates that
it is of the wrong dynamic type, or that its lifetime has not
begun or has ended. Incompatible with ``-fno-rtti``. Link must
be performed by ``clang++``, not ``clang``, to make sure C++-specific
parts of the runtime library and C++ standard libraries are present.
- ``-fsanitize=vptr``: Use of an object whose vptr indicates that it is of
the wrong dynamic type, or that its lifetime has not begun or has ended.
Incompatible with ``-fno-rtti``. Link must be performed by ``clang++``, not
``clang``, to make sure C++-specific parts of the runtime library and C++
standard libraries are present.
You can also use the following check groups:
- ``-fsanitize=undefined``: All of the checks listed above other than
@ -154,6 +156,19 @@ Volatile
The ``null``, ``alignment``, ``object-size``, and ``vptr`` checks do not apply
to pointers to types with the ``volatile`` qualifier.
Minimal Runtime
===============
There is a minimal UBSan runtime available suitable for use in production
environments. This runtime has a small attack surface. It only provides very
basic issue logging and deduplication, and does not support ``-fsanitize=vptr``
checking.
To use the minimal runtime, add ``-fsanitize-minimal-runtime`` to the clang
command line options. For example, if you're used to compiling with
``-fsanitize=undefined``, you could enable the minimal runtime with
``-fsanitize=undefined -fsanitize-minimal-runtime``.
Stack traces and report symbolization
=====================================
If you want UBSan to print symbolized stack trace for each error report, you

View File

@ -107,7 +107,7 @@ Options to Control Error and Warning Messages
.. option:: -Wno-error=foo
Turn warning "foo" into an warning even if :option:`-Werror` is specified.
Turn warning "foo" into a warning even if :option:`-Werror` is specified.
.. option:: -Wfoo
@ -677,7 +677,7 @@ Current limitations
Other Options
-------------
Clang options that that don't fit neatly into other categories.
Clang options that don't fit neatly into other categories.
.. option:: -MV
@ -1147,6 +1147,11 @@ are listed below.
the behavior of sanitizers in the ``cfi`` group to allow checking
of cross-DSO virtual and indirect calls.
.. option:: -fsanitize-cfi-icall-generalize-pointers
Generalize pointers in return and argument types in function type signatures
checked by Control Flow Integrity indirect call checking. See
:doc:`ControlFlowIntegrity` for more details.
.. option:: -fstrict-vtable-pointers
@ -1438,7 +1443,7 @@ Sample Profile Text Format
This section describes the ASCII text format for sampling profiles. It is,
arguably, the easiest one to generate. If you are interested in generating any
of the other two, consult the ``ProfileData`` library in in LLVM's source tree
of the other two, consult the ``ProfileData`` library in LLVM's source tree
(specifically, ``include/llvm/ProfileData/SampleProfReader.h``).
.. code-block:: console
@ -1454,7 +1459,7 @@ of the other two, consult the ``ProfileData`` library in in LLVM's source tree
offsetB[.discriminator]: fnB:num_of_total_samples
offsetB1[.discriminator]: number_of_samples [fn11:num fn12:num ... ]
This is a nested tree in which the identation represents the nesting level
This is a nested tree in which the indentation represents the nesting level
of the inline stack. There are no blank lines in the file. And the spacing
within a single line is fixed. Additional spaces will result in an error
while reading the file.

View File

@ -74,7 +74,7 @@ inspects expressions.)
ExprInspection checks
---------------------
- void clang_analyzer_eval(bool);
- ``void clang_analyzer_eval(bool);``
Prints TRUE if the argument is known to have a non-zero value, FALSE if the
argument is known to have a zero or null value, and UNKNOWN if the argument
@ -93,7 +93,7 @@ ExprInspection checks
clang_analyzer_eval(x); // expected-warning{{TRUE}}
- void clang_analyzer_checkInlined(bool);
- ``void clang_analyzer_checkInlined(bool);``
If a call occurs within an inlined function, prints TRUE or FALSE according to
the value of its argument. If a call occurs outside an inlined function,
@ -125,7 +125,7 @@ ExprInspection checks
clang_analyzer_eval(value == 42); // expected-warning{{TRUE}}
}
- void clang_analyzer_warnIfReached();
- ``void clang_analyzer_warnIfReached();``
Generate a warning if this line of code gets reached by the analyzer.
@ -138,7 +138,7 @@ ExprInspection checks
clang_analyzer_warnIfReached(); // no-warning
}
- void clang_analyzer_numTimesReached();
- ``void clang_analyzer_numTimesReached();``
Same as above, but include the number of times this call expression
gets reached by the analyzer during the current analysis.
@ -149,7 +149,7 @@ ExprInspection checks
clang_analyzer_numTimesReached(); // expected-warning{{3}}
}
- void clang_analyzer_warnOnDeadSymbol(int);
- ``void clang_analyzer_warnOnDeadSymbol(int);``
Subscribe for a delayed warning when the symbol that represents the value of
the argument is garbage-collected by the analyzer.
@ -173,7 +173,7 @@ ExprInspection checks
} while(0); // expected-warning{{SYMBOL DEAD}}
- void clang_analyzer_explain(a single argument of any type);
- ``void clang_analyzer_explain(a single argument of any type);``
This function explains the value of its argument in a human-readable manner
in the warning message. You can make as many overrides of its prototype
@ -197,7 +197,7 @@ ExprInspection checks
clang_analyzer_explain(ptr); // expected-warning{{memory address '0'}}
}
- void clang_analyzer_dump(a single argument of any type);
- ``void clang_analyzer_dump( /* a single argument of any type */);``
Similar to clang_analyzer_explain, but produces a raw dump of the value,
same as SVal::dump().
@ -209,7 +209,7 @@ ExprInspection checks
clang_analyzer_dump(x); // expected-warning{{reg_$0<x>}}
}
- size_t clang_analyzer_getExtent(void *);
- ``size_t clang_analyzer_getExtent(void *);``
This function returns the value that represents the extent of a memory region
pointed to by the argument. This value is often difficult to obtain otherwise,
@ -226,7 +226,7 @@ ExprInspection checks
clang_analyzer_explain(ys); // expected-warning{{'8'}}
}
- void clang_analyzer_printState();
- ``void clang_analyzer_printState();``
Dumps the current ProgramState to the stderr. Quickly lookup the program state
at any execution point without ViewExplodedGraph or re-compiling the program.
@ -242,6 +242,19 @@ ExprInspection checks
clang_analyzer_printState(); // Read the stderr!
}
- ``void clang_analyzer_hashDump(int);``
The analyzer can generate a hash to identify reports. To debug what information
is used to calculate this hash it is possible to dump the hashed string as a
warning of an arbitrary expression using the function above.
Example usage::
void foo() {
int x = 1;
clang_analyzer_hashDump(x); // expected-warning{{hashed string for x}}
}
Statistics
==========

View File

@ -0,0 +1,321 @@
This discussion took place in https://reviews.llvm.org/D35216
"Escape symbols when creating std::initializer_list".
It touches problems of modelling C++ standard library constructs in general,
including modelling implementation-defined fields within C++ standard library
objects, in particular constructing objects into pointers held by such fields,
and separation of responsibilities between analyzer's core and checkers.
**Artem:**
I've seen a few false positives that appear because we construct
C++11 std::initializer_list objects with brace initializers, and such
construction is not properly modeled. For instance, if a new object is
constructed on the heap only to be put into a brace-initialized STL container,
the object is reported to be leaked.
Approach (0): This can be trivially fixed by this patch, which causes pointers
passed into initializer list expressions to immediately escape.
This fix is overly conservative though. So i did a bit of investigation as to
how model std::initializer_list better.
According to the standard, std::initializer_list<T> is an object that has
methods begin(), end(), and size(), where begin() returns a pointer to continous
array of size() objects of type T, and end() is equal to begin() plus size().
The standard does hint that it should be possible to implement
std::initializer_list<T> as a pair of pointers, or as a pointer and a size
integer, however specific fields that the object would contain are an
implementation detail.
Ideally, we should be able to model the initializer list's methods precisely.
Or, at least, it should be possible to explain to the analyzer that the list
somehow "takes hold" of the values put into it. Initializer lists can also be
copied, which is a separate story that i'm not trying to address here.
The obvious approach to modeling std::initializer_list in a checker would be to
construct a SymbolMetadata for the memory region of the initializer list object,
which would be of type T* and represent begin(), so we'd trivially model begin()
as a function that returns this symbol. The array pointed to by that symbol
would be bindLoc()ed to contain the list's contents (probably as a CompoundVal
to produce less bindings in the store). Extent of this array would represent
size() and would be equal to the length of the list as written.
So this sounds good, however apparently it does nothing to address our false
positives: when the list escapes, our RegionStoreManager is not magically
guessing that the metadata symbol attached to it, together with its contents,
should also escape. In fact, it's impossible to trigger a pointer escape from
within the checker.
Approach (1): If only we enabled ProgramState::bindLoc(..., notifyChanges=true)
to cause pointer escapes (not only region changes) (which sounds like the right
thing to do anyway) such checker would be able to solve the false positives by
triggering escapes when binding list elements to the list. However, it'd be as
conservative as the current patch's solution. Ideally, we do not want escapes to
happen so early. Instead, we'd prefer them to be delayed until the list itself
escapes.
So i believe that escaping metadata symbols whenever their base regions escape
would be the right thing to do. Currently we didn't think about that because we
had neither pointer-type metadatas nor non-pointer escapes.
Approach (2): We could teach the Store to scan itself for bindings to
metadata-symbolic-based regions during scanReachableSymbols() whenever a region
turns out to be reachable. This requires no work on checker side, but it sounds
performance-heavy.
Approach (3): We could let checkers maintain the set of active metadata symbols
in the program state (ideally somewhere in the Store, which sounds weird but
causes the smallest amount of layering violations), so that the core knew what
to escape. This puts a stress on the checkers, but with a smart data map it
wouldn't be a problem.
Approach (4): We could allow checkers to trigger pointer escapes in arbitrary
moments. If we allow doing this within checkPointerEscape callback itself, we
would be able to express facts like "when this region escapes, that metadata
symbol attached to it should also escape". This sounds like an ultimate freedom,
with maximum stress on the checkers - still not too much stress when we have
smart data maps.
I'm personally liking the approach (2) - it should be possible to avoid
performance overhead, and clarity seems nice.
**Gabor:**
At this point, I am a bit wondering about two questions.
- When should something belong to a checker and when should something belong
to the engine? Sometimes we model library aspects in the engine and model
language constructs in checkers.
- What is the checker programming model that we are aiming for? Maximum
freedom or more easy checker development?
I think if we aim for maximum freedom, we do not need to worry about the
potential stress on checkers, and we can introduce abstractions to mitigate that
later on.
If we want to simplify the API, then maybe it makes more sense to move language
construct modeling to the engine when the checker API is not sufficient instead
of complicating the API.
Right now I have no preference or objections between the alternatives but there
are some random thoughts:
- Maybe it would be great to have a guideline how to evolve the analyzer and
follow it, so it can help us to decide in similar situations
- I do care about performance in this case. The reason is that we have a
limited performance budget. And I think we should not expect most of the checker
writers to add modeling of language constructs. So, in my opinion, it is ok to
have less nice/more verbose API for language modeling if we can have better
performance this way, since it only needs to be done once, and is done by the
framework developers.
**Artem:** These are some great questions, i guess it'd be better to discuss
them more openly. As a quick dump of my current mood:
- To me it seems obvious that we need to aim for a checker API that is both
simple and powerful. This can probably by keeping the API as powerful as
necessary while providing a layer of simple ready-made solutions on top of it.
Probably a few reusable components for assembling checkers. And this layer
should ideally be pleasant enough to work with, so that people would prefer to
extend it when something is lacking, instead of falling back to the complex
omnipotent API. I'm thinking of AST matchers vs. AST visitors as a roughly
similar situation: matchers are not omnipotent, but they're so nice.
- Separation between core and checkers is usually quite strange. Once we have
shared state traits, i generally wouldn't mind having region store or range
constraint manager as checkers (though it's probably not worth it to transform
them - just a mood). The main thing to avoid here would be the situation when
the checker overwrites stuff written by the core because it thinks it has a
better idea what's going on, so the core should provide a good default behavior.
- Yeah, i totally care about performance as well, and if i try to implement
approach, i'd make sure it's good.
**Artem:**
> Approach (2): We could teach the Store to scan itself for bindings to
> metadata-symbolic-based regions during scanReachableSymbols() whenever
> a region turns out to be reachable. This requires no work on checker side,
> but it sounds performance-heavy.
Nope, this approach is wrong. Metadata symbols may become out-of-date: when the
object changes, metadata symbols attached to it aren't changing (because symbols
simply don't change). The same metadata may have different symbols to denote its
value in different moments of time, but at most one of them represents the
actual metadata value. So we'd be escaping more stuff than necessary.
If only we had "ghost fields"
(http://lists.llvm.org/pipermail/cfe-dev/2016-May/049000.html), it would have
been much easier, because the ghost field would only contain the actual
metadata, and the Store would always know about it. This example adds to my
belief that ghost fields are exactly what we need for most C++ checkers.
**Devin:**
In this case, I would be fine with some sort of
AbstractStorageMemoryRegion that meant "here is a memory region and somewhere
reachable from here exists another region of type T". Or even multiple regions
with different identifiers. This wouldn't specify how the memory is reachable,
but it would allow for transfer functions to get at those regions and it would
allow for invalidation.
For std::initializer_list this reachable region would the region for the backing
array and the transfer functions for begin() and end() yield the beginning and
end element regions for it.
In my view this differs from ghost variables in that (1) this storage does
actually exist (it is just a library implementation detail where that storage
lives) and (2) it is perfectly valid for a pointer into that storage to be
returned and for another part of the program to read or write from that storage.
(Well, in this case just read since it is allowed to be read-only memory).
What I'm not OK with is modeling abstract analysis state (for example, the count
of a NSMutableArray or the typestate of a file handle) as a value stored in some
ginned up region in the store. This takes an easy problem that the analyzer does
well at (modeling typestate) and turns it into a hard one that the analyzer is
bad at (reasoning about the contents of the heap).
I think the key criterion here is: "is the region accessible from outside the
library". That is, does the library expose the region as a pointer that can be
read to or written from in the client program? If so, then it makes sense for
this to be in the store: we are modeling reachable storage as storage. But if
we're just modeling arbitrary analysis facts that need to be invalidated when a
pointer escapes then we shouldn't try to gin up storage for them just to get
invalidation for free.
**Artem:**
> In this case, I would be fine with some sort of AbstractStorageMemoryRegion
> that meant "here is a memory region and somewhere reachable from here exists
> another region of type T". Or even multiple regions with different
> identifiers. This wouldn't specify how the memory is reachable, but it would
> allow for transfer functions to get at those regions and it would allow for
> invalidation.
Yeah, this is what we can easily implement now as a
symbolic-region-based-on-a-metadata-symbol (though we can make a new region
class for that if we eg. want it typed). The problem is that the relation
between such storage region and its parent object region is essentially
immaterial, similarly to the relation between SymbolRegionValue and its parent
region. Region contents are mutable: today the abstract storage is reachable
from its parent object, tomorrow it's not, and maybe something else becomes
reachable, something that isn't even abstract. So the parent region for the
abstract storage is most of the time at best a "nice to know" thing - we cannot
rely on it to do any actual work. We'd anyway need to rely on the checker to do
the job.
> For std::initializer_list this reachable region would the region for the
> backing array and the transfer functions for begin() and end() yield the
> beginning and end element regions for it.
So maybe in fact for std::initializer_list it may work fine because you cannot
change the data after the object is constructed - so this region's contents are
essentially immutable. For the future, i feel as if it is a dead end.
I'd like to consider another funny example. Suppose we're trying to model
std::unique_ptr. Consider::
void bar(const std::unique_ptr<int> &x);
void foo(std::unique_ptr<int> &x) {
int *a = x.get(); // (a, 0, direct): &AbstractStorageRegion
*a = 1; // (AbstractStorageRegion, 0, direct): 1 S32b
int *b = new int;
*b = 2; // (SymRegion{conj_$0<int *>}, 0 ,direct): 2 S32b
x.reset(b); // Checker map: x -> SymRegion{conj_$0<int *>}
bar(x); // 'a' doesn't escape (the pointer was unique), 'b' does.
clang_analyzer_eval(*a == 1); // Making this true is up to the checker.
clang_analyzer_eval(*b == 2); // Making this unknown is up to the checker.
}
The checker doesn't totally need to ensure that *a == 1 passes - even though the
pointer was unique, it could theoretically have .get()-ed above and the code
could of course break the uniqueness invariant (though we'd probably want it).
The checker can say that "even if *a did escape, it was not because it was
stuffed directly into bar()".
The checker's direct responsibility, however, is to solve the *b == 2 thing
(which is in fact the problem we're dealing with in this patch - escaping the
storage region of the object).
So we're talking about one more operation over the program state (scanning
reachable symbols and regions) that cannot work without checker support.
We can probably add a new callback "checkReachableSymbols" to solve this. This
is in fact also related to the dead symbols problem (we're scanning for live
symbols in the store and in the checkers separately, but we need to do so
simultaneously with a single worklist). Hmm, in fact this sounds like a good
idea; we can replace checkLiveSymbols with checkReachableSymbols.
Or we could just have ghost member variables, and no checker support required at
all. For ghost member variables, the relation with their parent region (which
would be their superregion) is actually useful, the mutability of their contents
is expressed naturally, and the store automagically sees reachable symbols, live
symbols, escapes, invalidations, whatever.
> In my view this differs from ghost variables in that (1) this storage does
> actually exist (it is just a library implementation detail where that storage
> lives) and (2) it is perfectly valid for a pointer into that storage to be
> returned and for another part of the program to read or write from that
> storage. (Well, in this case just read since it is allowed to be read-only
> memory).
> What I'm not OK with is modeling abstract analysis state (for example, the
> count of a NSMutableArray or the typestate of a file handle) as a value stored
> in some ginned up region in the store.This takes an easy problem that the
> analyzer does well at (modeling typestate) and turns it into a hard one that
> the analyzer is bad at (reasoning about the contents of the heap).
Yeah, i tend to agree on that. For simple typestates, this is probably an
overkill, so let's definitely put aside the idea of "ghost symbolic regions"
that i had earlier.
But, to summarize a bit, in our current case, however, the typestate we're
looking for is the contents of the heap. And when we try to model such
typestates (complex in this specific manner, i.e. heap-like) in any checker, we
have a choice between re-doing this modeling in every such checker (which is
something analyzer is indeed good at, but at a price of making checkers heavy)
or instead relying on the Store to do exactly what it's designed to do.
> I think the key criterion here is: "is the region accessible from outside
> the library". That is, does the library expose the region as a pointer that
> can be read to or written from in the client program? If so, then it makes
> sense for this to be in the store: we are modeling reachable storage as
> storage. But if we're just modeling arbitrary analysis facts that need to be
> invalidated when a pointer escapes then we shouldn't try to gin up storage
> for them just to get invalidation for free.
As a metaphor, i'd probably compare it to body farms - the difference between
ghost member variables and metadata symbols seems to me like the difference
between body farms and evalCall. Both are nice to have, and body farms are very
pleasant to work with, even if not omnipotent. I think it's fine for a
FunctionDecl's body in a body farm to have a local variable, even if such
variable doesn't actually exist, even if it cannot be seen from outside the
function call. I'm not seeing immediate practical difference between "it does
actually exist" and "it doesn't actually exist, just a handy abstraction".
Similarly, i think it's fine if we have a CXXRecordDecl with
implementation-defined contents, and try to farm up a member variable as a handy
abstraction (we don't even need to know its name or offset, only that it's there
somewhere).
**Artem:**
We've discussed it in person with Devin, and he provided more points to think
about:
- If the initializer list consists of non-POD data, constructors of list's
objects need to take the sub-region of the list's region as this-region In the
current (v2) version of this patch, these objects are constructed elsewhere and
then trivial-copied into the list's metadata pointer region, which may be
incorrect. This is our overall problem with C++ constructors, which manifests in
this case as well. Additionally, objects would need to be constructed in the
analyzer's core, which would not be able to predict that it needs to take a
checker-specific region as this-region, which makes it harder, though it might
be mitigated by sharing the checker state traits.
- Because "ghost variables" are not material to the user, we need to somehow
make super sure that they don't make it into the diagnostic messages.
So, because this needs further digging into overall C++ support and rises too
many questions, i'm delaying a better approach to this problem and will fall
back to the original trivial patch.

View File

@ -49,9 +49,9 @@
# built documents.
#
# The short version.
version = '5'
version = '6'
# The full version, including alpha/beta/rc tags.
release = '5'
release = '6'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.

View File

@ -49,9 +49,9 @@
# built documents.
#
# The short version.
version = '5'
version = '6'
# The full version, including alpha/beta/rc tags.
release = '5'
release = '6'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.

View File

@ -60,6 +60,7 @@ Using Clang as a Library
LibASTMatchers
HowToSetupToolingForLLVM
JSONCompilationDatabase
RefactoringEngine
Using Clang Tools
=================
@ -83,6 +84,7 @@ Design Documents
PTHInternals
PCHInternals
ItaniumMangleAbiTags
HardwareAssistedAddressSanitizerDesign.rst
Indices and tables

View File

@ -177,7 +177,8 @@ class State:
for option in options:
if not option.type in ['bool', 'unsigned', 'int', 'std::string',
'std::vector<std::string>',
'std::vector<IncludeCategory>']:
'std::vector<IncludeCategory>',
'std::vector<RawStringFormat>']:
if enums.has_key(option.type):
option.enum = enums[option.type]
elif nested_structs.has_key(option.type):

View File

@ -17,6 +17,7 @@ add_dependencies(clang-interpreter
)
target_link_libraries(clang-interpreter
PRIVATE
clangBasic
clangCodeGen
clangDriver

View File

@ -32,7 +32,7 @@
* compatible, thus CINDEX_VERSION_MAJOR is expected to remain stable.
*/
#define CINDEX_VERSION_MAJOR 0
#define CINDEX_VERSION_MINOR 43
#define CINDEX_VERSION_MINOR 45
#define CINDEX_VERSION_ENCODE(major, minor) ( \
((major) * 10000) \
@ -333,6 +333,16 @@ CINDEX_LINKAGE void clang_CXIndex_setGlobalOptions(CXIndex, unsigned options);
*/
CINDEX_LINKAGE unsigned clang_CXIndex_getGlobalOptions(CXIndex);
/**
* \brief Sets the invocation emission path option in a CXIndex.
*
* The invocation emission path specifies a path which will contain log
* files for certain libclang invocations. A null value (default) implies that
* libclang invocations are not logged..
*/
CINDEX_LINKAGE void
clang_CXIndex_setInvocationEmissionPathOption(CXIndex, const char *Path);
/**
* \defgroup CINDEX_FILES File manipulation routines
*
@ -393,6 +403,21 @@ clang_isFileMultipleIncludeGuarded(CXTranslationUnit tu, CXFile file);
CINDEX_LINKAGE CXFile clang_getFile(CXTranslationUnit tu,
const char *file_name);
/**
* \brief Retrieve the buffer associated with the given file.
*
* \param tu the translation unit
*
* \param file the file for which to retrieve the buffer.
*
* \param size [out] if non-NULL, will be set to the size of the buffer.
*
* \returns a pointer to the buffer in memory that holds the contents of
* \p file, or a NULL pointer when the file is not loaded.
*/
CINDEX_LINKAGE const char *clang_getFileContents(CXTranslationUnit tu,
CXFile file, size_t *size);
/**
* \brief Returns non-zero if the \c file1 and \c file2 point to the same file,
* or they are both NULL.
@ -2836,6 +2861,22 @@ enum CXLanguageKind {
*/
CINDEX_LINKAGE enum CXLanguageKind clang_getCursorLanguage(CXCursor cursor);
/**
* \brief Describe the "thread-local storage (TLS) kind" of the declaration
* referred to by a cursor.
*/
enum CXTLSKind {
CXTLS_None = 0,
CXTLS_Dynamic,
CXTLS_Static
};
/**
* \brief Determine the "thread-local storage (TLS) kind" of the declaration
* referred to by a cursor.
*/
CINDEX_LINKAGE enum CXTLSKind clang_getCursorTLSKind(CXCursor cursor);
/**
* \brief Returns the translation unit that a cursor originated from.
*/
@ -3115,8 +3156,9 @@ enum CXTypeKind {
CXType_ObjCSel = 29,
CXType_Float128 = 30,
CXType_Half = 31,
CXType_Float16 = 32,
CXType_FirstBuiltin = CXType_Void,
CXType_LastBuiltin = CXType_Half,
CXType_LastBuiltin = CXType_Float16,
CXType_Complex = 100,
CXType_Pointer = 101,
@ -4275,6 +4317,12 @@ CINDEX_LINKAGE CXString clang_Cursor_getMangling(CXCursor);
*/
CINDEX_LINKAGE CXStringSet *clang_Cursor_getCXXManglings(CXCursor);
/**
* \brief Retrieve the CXStrings representing the mangled symbols of the ObjC
* class interface or implementation at the cursor.
*/
CINDEX_LINKAGE CXStringSet *clang_Cursor_getObjCManglings(CXCursor);
/**
* @}
*/
@ -4418,6 +4466,12 @@ CINDEX_LINKAGE unsigned clang_CXXMethod_isStatic(CXCursor C);
*/
CINDEX_LINKAGE unsigned clang_CXXMethod_isVirtual(CXCursor C);
/**
* \brief Determine if a C++ record is abstract, i.e. whether a class or struct
* has a pure virtual member function.
*/
CINDEX_LINKAGE unsigned clang_CXXRecord_isAbstract(CXCursor C);
/**
* \brief Determine if an enum declaration refers to a scoped enum.
*/

View File

@ -1,4 +1,4 @@
//===--- ASTContext.h - Context to hold long-lived AST nodes ----*- C++ -*-===//
//===- ASTContext.h - Context to hold long-lived AST nodes ------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@ -6,10 +6,10 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
//
/// \file
/// \brief Defines the clang::ASTContext interface.
///
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_AST_ASTCONTEXT_H
@ -19,8 +19,8 @@
#include "clang/AST/CanonicalType.h"
#include "clang/AST/CommentCommandTraits.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclarationName.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclarationName.h"
#include "clang/AST/ExternalASTSource.h"
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/PrettyPrinter.h"
@ -30,32 +30,32 @@
#include "clang/AST/Type.h"
#include "clang/Basic/AddressSpaces.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/Linkage.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/Module.h"
#include "clang/Basic/OperatorKinds.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/SanitizerBlacklist.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/Specifiers.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/XRayLists.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/iterator_range.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/None.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/TinyPtrVector.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/TinyPtrVector.h"
#include "llvm/ADT/Triple.h"
#include "llvm/ADT/iterator_range.h"
#include "llvm/Support/AlignOf.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/Casting.h"
@ -65,7 +65,6 @@
#include <cstdint>
#include <iterator>
#include <memory>
#include <new>
#include <string>
#include <type_traits>
#include <utility>
@ -75,50 +74,72 @@ namespace llvm {
struct fltSemantics;
} // end namespace llvm
} // namespace llvm
namespace clang {
class APValue;
class ASTMutationListener;
class ASTRecordLayout;
class AtomicExpr;
class BlockExpr;
class BuiltinTemplateDecl;
class CharUnits;
class CXXABI;
class CXXConstructorDecl;
class CXXMethodDecl;
class CXXRecordDecl;
class DiagnosticsEngine;
class Expr;
class MangleContext;
class MangleNumberingContext;
class MaterializeTemporaryExpr;
class TargetInfo;
// Decls
class MangleContext;
class MemberSpecializationInfo;
class Module;
class ObjCCategoryDecl;
class ObjCCategoryImplDecl;
class ObjCContainerDecl;
class ObjCImplDecl;
class ObjCImplementationDecl;
class ObjCInterfaceDecl;
class ObjCIvarDecl;
class ObjCMethodDecl;
class ObjCPropertyDecl;
class ObjCPropertyImplDecl;
class ObjCProtocolDecl;
class ObjCTypeParamDecl;
class Preprocessor;
class Stmt;
class StoredDeclsMap;
class TemplateDecl;
class TemplateParameterList;
class TemplateTemplateParmDecl;
class TemplateTypeParmDecl;
class UnresolvedSetIterator;
class UsingDecl;
class UsingShadowDecl;
class VarTemplateDecl;
class VTableContextBase;
namespace Builtin {
class Context;
class Context;
} // end namespace Builtin
} // namespace Builtin
enum BuiltinTemplateKind : int;
namespace comments {
class FullComment;
class FullComment;
} // end namespace comments
} // namespace comments
struct TypeInfo {
uint64_t Width;
unsigned Align;
uint64_t Width = 0;
unsigned Align = 0;
bool AlignIsRequired : 1;
TypeInfo() : Width(0), Align(0), AlignIsRequired(false) {}
TypeInfo() : AlignIsRequired(false) {}
TypeInfo(uint64_t Width, unsigned Align, bool AlignIsRequired)
: Width(Width), Align(Align), AlignIsRequired(AlignIsRequired) {}
};
@ -126,7 +147,7 @@ struct TypeInfo {
/// \brief 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> {
ASTContext &this_() { return *this; }
friend class NestedNameSpecifier;
mutable SmallVector<Type *, 0> Types;
mutable llvm::FoldingSet<ExtQuals> ExtQualNodes;
@ -143,6 +164,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
mutable llvm::FoldingSet<DependentSizedArrayType> DependentSizedArrayTypes;
mutable llvm::FoldingSet<DependentSizedExtVectorType>
DependentSizedExtVectorTypes;
mutable llvm::FoldingSet<DependentAddressSpaceType>
DependentAddressSpaceTypes;
mutable llvm::FoldingSet<VectorType> VectorTypes;
mutable llvm::FoldingSet<FunctionNoProtoType> FunctionNoProtoTypes;
mutable llvm::ContextualFoldingSet<FunctionProtoType, ASTContext&>
@ -187,8 +210,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
///
/// This set is managed by the NestedNameSpecifier class.
mutable llvm::FoldingSet<NestedNameSpecifier> NestedNameSpecifiers;
mutable NestedNameSpecifier *GlobalNestedNameSpecifier;
friend class NestedNameSpecifier;
mutable NestedNameSpecifier *GlobalNestedNameSpecifier = nullptr;
/// \brief A cache mapping from RecordDecls to ASTRecordLayouts.
///
@ -199,7 +221,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
ObjCLayouts;
/// \brief A cache from types to size and alignment information.
typedef llvm::DenseMap<const Type *, struct TypeInfo> TypeInfoMap;
using TypeInfoMap = llvm::DenseMap<const Type *, struct TypeInfo>;
mutable TypeInfoMap MemoizedTypeInfo;
/// \brief A cache mapping from CXXRecordDecls to key functions.
@ -233,7 +255,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
public:
CanonicalTemplateTemplateParm(TemplateTemplateParmDecl *Parm)
: Parm(Parm) { }
: Parm(Parm) {}
TemplateTemplateParmDecl *getParam() const { return Parm; }
@ -249,32 +271,32 @@ class ASTContext : public RefCountedBase<ASTContext> {
getCanonicalTemplateTemplateParmDecl(TemplateTemplateParmDecl *TTP) const;
/// \brief The typedef for the __int128_t type.
mutable TypedefDecl *Int128Decl;
mutable TypedefDecl *Int128Decl = nullptr;
/// \brief The typedef for the __uint128_t type.
mutable TypedefDecl *UInt128Decl;
mutable TypedefDecl *UInt128Decl = nullptr;
/// \brief The typedef for the target specific predefined
/// __builtin_va_list type.
mutable TypedefDecl *BuiltinVaListDecl;
mutable TypedefDecl *BuiltinVaListDecl = nullptr;
/// The typedef for the predefined \c __builtin_ms_va_list type.
mutable TypedefDecl *BuiltinMSVaListDecl;
mutable TypedefDecl *BuiltinMSVaListDecl = nullptr;
/// \brief The typedef for the predefined \c id type.
mutable TypedefDecl *ObjCIdDecl;
mutable TypedefDecl *ObjCIdDecl = nullptr;
/// \brief The typedef for the predefined \c SEL type.
mutable TypedefDecl *ObjCSelDecl;
mutable TypedefDecl *ObjCSelDecl = nullptr;
/// \brief The typedef for the predefined \c Class type.
mutable TypedefDecl *ObjCClassDecl;
mutable TypedefDecl *ObjCClassDecl = nullptr;
/// \brief The typedef for the predefined \c Protocol class in Objective-C.
mutable ObjCInterfaceDecl *ObjCProtocolClassDecl;
mutable ObjCInterfaceDecl *ObjCProtocolClassDecl = nullptr;
/// \brief The typedef for the predefined 'BOOL' type.
mutable TypedefDecl *BOOLDecl;
mutable TypedefDecl *BOOLDecl = nullptr;
// Typedefs which may be provided defining the structure of Objective-C
// pseudo-builtins
@ -298,42 +320,42 @@ class ASTContext : public RefCountedBase<ASTContext> {
mutable IdentifierInfo *TypePackElementName = nullptr;
QualType ObjCConstantStringType;
mutable RecordDecl *CFConstantStringTagDecl;
mutable TypedefDecl *CFConstantStringTypeDecl;
mutable RecordDecl *CFConstantStringTagDecl = nullptr;
mutable TypedefDecl *CFConstantStringTypeDecl = nullptr;
mutable QualType ObjCSuperType;
QualType ObjCNSStringType;
/// \brief The typedef declaration for the Objective-C "instancetype" type.
TypedefDecl *ObjCInstanceTypeDecl;
TypedefDecl *ObjCInstanceTypeDecl = nullptr;
/// \brief The type for the C FILE type.
TypeDecl *FILEDecl;
TypeDecl *FILEDecl = nullptr;
/// \brief The type for the C jmp_buf type.
TypeDecl *jmp_bufDecl;
TypeDecl *jmp_bufDecl = nullptr;
/// \brief The type for the C sigjmp_buf type.
TypeDecl *sigjmp_bufDecl;
TypeDecl *sigjmp_bufDecl = nullptr;
/// \brief The type for the C ucontext_t type.
TypeDecl *ucontext_tDecl;
TypeDecl *ucontext_tDecl = nullptr;
/// \brief Type for the Block descriptor for Blocks CodeGen.
///
/// Since this is only used for generation of debug info, it is not
/// serialized.
mutable RecordDecl *BlockDescriptorType;
mutable RecordDecl *BlockDescriptorType = nullptr;
/// \brief Type for the Block descriptor for Blocks CodeGen.
///
/// Since this is only used for generation of debug info, it is not
/// serialized.
mutable RecordDecl *BlockDescriptorExtendedType;
mutable RecordDecl *BlockDescriptorExtendedType = nullptr;
/// \brief Declaration for the CUDA cudaConfigureCall function.
FunctionDecl *cudaConfigureCallDecl;
FunctionDecl *cudaConfigureCallDecl = nullptr;
/// \brief Keeps track of all declaration attributes.
///
@ -363,12 +385,19 @@ class ASTContext : public RefCountedBase<ASTContext> {
};
llvm::DenseMap<Module*, PerModuleInitializers*> ModuleInitializers;
ASTContext &this_() { return *this; }
public:
/// \brief A type synonym for the TemplateOrInstantiation mapping.
typedef llvm::PointerUnion<VarTemplateDecl *, MemberSpecializationInfo *>
TemplateOrSpecializationInfo;
using TemplateOrSpecializationInfo =
llvm::PointerUnion<VarTemplateDecl *, MemberSpecializationInfo *>;
private:
friend class ASTDeclReader;
friend class ASTReader;
friend class ASTWriter;
friend class CXXRecordDecl;
/// \brief A mapping to contain the template or declaration that
/// a variable declaration describes or was instantiated from,
/// respectively.
@ -438,7 +467,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// Since most C++ member functions aren't virtual and therefore
/// don't override anything, we store the overridden functions in
/// this map on the side rather than within the CXXMethodDecl structure.
typedef llvm::TinyPtrVector<const CXXMethodDecl*> CXXMethodVector;
using CXXMethodVector = llvm::TinyPtrVector<const CXXMethodDecl *>;
llvm::DenseMap<const CXXMethodDecl *, CXXMethodVector> OverriddenMethods;
/// \brief Mapping from each declaration context to its corresponding
@ -454,18 +483,18 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// \brief Mapping that stores parameterIndex values for ParmVarDecls when
/// that value exceeds the bitfield size of ParmVarDeclBits.ParameterIndex.
typedef llvm::DenseMap<const VarDecl *, unsigned> ParameterIndexTable;
using ParameterIndexTable = llvm::DenseMap<const VarDecl *, unsigned>;
ParameterIndexTable ParamIndices;
ImportDecl *FirstLocalImport;
ImportDecl *LastLocalImport;
ImportDecl *FirstLocalImport = nullptr;
ImportDecl *LastLocalImport = nullptr;
TranslationUnitDecl *TUDecl;
mutable ExternCContextDecl *ExternCContext;
mutable BuiltinTemplateDecl *MakeIntegerSeqDecl;
mutable BuiltinTemplateDecl *TypePackElementDecl;
mutable ExternCContextDecl *ExternCContext = nullptr;
mutable BuiltinTemplateDecl *MakeIntegerSeqDecl = nullptr;
mutable BuiltinTemplateDecl *TypePackElementDecl = nullptr;
/// \brief The associated SourceManager object.a
/// \brief The associated SourceManager object.
SourceManager &SourceMgr;
/// \brief The language options used to create the AST associated with
@ -494,19 +523,14 @@ class ASTContext : public RefCountedBase<ASTContext> {
CXXABI *createCXXABI(const TargetInfo &T);
/// \brief The logical -> physical address space map.
const LangAS::Map *AddrSpaceMap;
const LangASMap *AddrSpaceMap = nullptr;
/// \brief Address space map mangling must be used with language specific
/// address spaces (e.g. OpenCL/CUDA)
bool AddrSpaceMapMangling;
friend class ASTDeclReader;
friend class ASTReader;
friend class ASTWriter;
friend class CXXRecordDecl;
const TargetInfo *Target;
const TargetInfo *AuxTarget;
const TargetInfo *Target = nullptr;
const TargetInfo *AuxTarget = nullptr;
clang::PrintingPolicy PrintingPolicy;
public:
@ -515,31 +539,33 @@ class ASTContext : public RefCountedBase<ASTContext> {
Builtin::Context &BuiltinInfo;
mutable DeclarationNameTable DeclarationNames;
IntrusiveRefCntPtr<ExternalASTSource> ExternalSource;
ASTMutationListener *Listener;
ASTMutationListener *Listener = nullptr;
/// \brief Contains parents of a node.
typedef llvm::SmallVector<ast_type_traits::DynTypedNode, 2> ParentVector;
using ParentVector = llvm::SmallVector<ast_type_traits::DynTypedNode, 2>;
/// \brief Maps from a node to its parents. This is used for nodes that have
/// pointer identity only, which are more common and we can save space by
/// only storing a unique pointer to them.
typedef llvm::DenseMap<const void *,
llvm::PointerUnion4<const Decl *, const Stmt *,
ast_type_traits::DynTypedNode *,
ParentVector *>> ParentMapPointers;
using ParentMapPointers =
llvm::DenseMap<const void *,
llvm::PointerUnion4<const Decl *, const Stmt *,
ast_type_traits::DynTypedNode *,
ParentVector *>>;
/// Parent map for nodes without pointer identity. We store a full
/// DynTypedNode for all keys.
typedef llvm::DenseMap<
ast_type_traits::DynTypedNode,
llvm::PointerUnion4<const Decl *, const Stmt *,
ast_type_traits::DynTypedNode *, ParentVector *>>
ParentMapOtherNodes;
using ParentMapOtherNodes =
llvm::DenseMap<ast_type_traits::DynTypedNode,
llvm::PointerUnion4<const Decl *, const Stmt *,
ast_type_traits::DynTypedNode *,
ParentVector *>>;
/// Container for either a single DynTypedNode or for an ArrayRef to
/// DynTypedNode. For use with ParentMap.
class DynTypedNodeList {
typedef ast_type_traits::DynTypedNode DynTypedNode;
using DynTypedNode = ast_type_traits::DynTypedNode;
llvm::AlignedCharArrayUnion<ast_type_traits::DynTypedNode,
ArrayRef<DynTypedNode>> Storage;
bool IsSingleNode;
@ -548,6 +574,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
DynTypedNodeList(const DynTypedNode &N) : IsSingleNode(true) {
new (Storage.buffer) DynTypedNode(N);
}
DynTypedNodeList(ArrayRef<DynTypedNode> A) : IsSingleNode(false) {
new (Storage.buffer) ArrayRef<DynTypedNode>(A);
}
@ -626,13 +653,14 @@ class ASTContext : public RefCountedBase<ASTContext> {
template <typename T> T *Allocate(size_t Num = 1) const {
return static_cast<T *>(Allocate(Num * sizeof(T), alignof(T)));
}
void Deallocate(void *Ptr) const { }
void Deallocate(void *Ptr) const {}
/// Return the total amount of physical memory allocated for representing
/// AST nodes and type information.
size_t getASTAllocatedMemory() const {
return BumpAlloc.getTotalMemory();
}
/// Return the total memory used for various side tables.
size_t getSideTableAllocatedMemory() const;
@ -649,6 +677,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// Returns empty type if there is no appropriate target types.
QualType getIntTypeForBitwidth(unsigned DestWidth,
unsigned Signed) const;
/// getRealTypeForBitwidth -
/// sets floating point QualTy according to specified bitwidth.
/// Returns empty type if there is no appropriate target types.
@ -676,7 +705,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
RawCommentList Comments;
/// \brief True if comments are already loaded from ExternalASTSource.
mutable bool CommentsLoaded;
mutable bool CommentsLoaded = false;
class RawCommentAndCacheFlags {
public:
@ -759,24 +788,24 @@ class ASTContext : public RefCountedBase<ASTContext> {
}
/// \brief Return the documentation comment attached to a given declaration.
/// Returns NULL if no comment is attached.
/// Returns nullptr if no comment is attached.
///
/// \param OriginalDecl if not NULL, is set to declaration AST node that had
/// the comment, if the comment we found comes from a redeclaration.
/// \param OriginalDecl if not nullptr, is set to declaration AST node that
/// had the comment, if the comment we found comes from a redeclaration.
const RawComment *
getRawCommentForAnyRedecl(const Decl *D,
const Decl **OriginalDecl = nullptr) const;
/// Return parsed documentation comment attached to a given declaration.
/// Returns NULL if no comment is attached.
/// Returns nullptr if no comment is attached.
///
/// \param PP the Preprocessor used with this TU. Could be NULL if
/// \param PP the Preprocessor used with this TU. Could be nullptr if
/// preprocessor is not available.
comments::FullComment *getCommentForDecl(const Decl *D,
const Preprocessor *PP) const;
/// Return parsed documentation comment attached to a given declaration.
/// Returns NULL if no comment is attached. Does not look at any
/// Returns nullptr if no comment is attached. Does not look at any
/// redeclarations of the declaration.
comments::FullComment *getLocalCommentForDeclUncached(const Decl *D) const;
@ -788,16 +817,16 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// \brief Iterator that visits import declarations.
class import_iterator {
ImportDecl *Import;
ImportDecl *Import = nullptr;
public:
typedef ImportDecl *value_type;
typedef ImportDecl *reference;
typedef ImportDecl *pointer;
typedef int difference_type;
typedef std::forward_iterator_tag iterator_category;
using value_type = ImportDecl *;
using reference = ImportDecl *;
using pointer = ImportDecl *;
using difference_type = int;
using iterator_category = std::forward_iterator_tag;
import_iterator() : Import() {}
import_iterator() = default;
explicit import_iterator(ImportDecl *Import) : Import(Import) {}
reference operator*() const { return Import; }
@ -876,7 +905,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
void setInstantiatedFromUnnamedFieldDecl(FieldDecl *Inst, FieldDecl *Tmpl);
// Access to the set of methods overridden by the given C++ method.
typedef CXXMethodVector::const_iterator overridden_cxx_method_iterator;
using overridden_cxx_method_iterator = CXXMethodVector::const_iterator;
overridden_cxx_method_iterator
overridden_methods_begin(const CXXMethodDecl *Method) const;
@ -884,8 +913,10 @@ class ASTContext : public RefCountedBase<ASTContext> {
overridden_methods_end(const CXXMethodDecl *Method) const;
unsigned overridden_methods_size(const CXXMethodDecl *Method) const;
typedef llvm::iterator_range<overridden_cxx_method_iterator>
overridden_method_range;
using overridden_method_range =
llvm::iterator_range<overridden_cxx_method_iterator>;
overridden_method_range overridden_methods(const CXXMethodDecl *Method) const;
/// \brief Note that the given C++ \p Method overrides the given \p
@ -912,7 +943,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
return Import->NextLocalImport;
}
typedef llvm::iterator_range<import_iterator> import_range;
using import_range = llvm::iterator_range<import_iterator>;
import_range local_imports() const {
return import_range(import_iterator(FirstLocalImport), import_iterator());
}
@ -929,6 +961,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// and should be visible whenever \p M is visible.
void mergeDefinitionIntoModule(NamedDecl *ND, Module *M,
bool NotifyListeners = true);
/// \brief Clean up the merged definition list. Call this if you might have
/// added duplicates into the list.
void deduplicateMergedDefinitonsFor(NamedDecl *ND);
@ -973,6 +1006,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
CanQualType UnsignedLongLongTy, UnsignedInt128Ty;
CanQualType FloatTy, DoubleTy, LongDoubleTy, Float128Ty;
CanQualType HalfTy; // [OpenCL 6.1.1.1], ARM NEON
CanQualType Float16Ty; // C11 extension ISO/IEC TS 18661-3
CanQualType FloatComplexTy, DoubleComplexTy, LongDoubleComplexTy;
CanQualType Float128ComplexTy;
CanQualType VoidPtrTy, NullPtrTy;
@ -1067,7 +1101,14 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// The resulting type has a union of the qualifiers from T and the address
/// space. If T already has an address space specifier, it is silently
/// replaced.
QualType getAddrSpaceQualType(QualType T, unsigned AddressSpace) const;
QualType getAddrSpaceQualType(QualType T, LangAS AddressSpace) const;
/// \brief Remove any existing address space on the type and returns the type
/// with qualifiers intact (or that's the idea anyway)
///
/// The return type should be T with all prior qualifiers minus the address
/// space.
QualType removeAddrSpaceQualType(QualType T) const;
/// \brief Apply Objective-C protocol qualifiers to the given type.
/// \param allowOnPointerType specifies if we can apply protocol
@ -1175,6 +1216,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// \brief Return a read_only pipe type for the specified type.
QualType getReadPipeType(QualType T) const;
/// \brief Return a write_only pipe type for the specified type.
QualType getWritePipeType(QualType T) const;
@ -1182,9 +1224,16 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// pointer to blocks.
QualType getBlockDescriptorExtendedType() const;
/// Map an AST Type to an OpenCLTypeKind enum value.
TargetInfo::OpenCLTypeKind getOpenCLTypeKind(const Type *T) const;
/// Get address space for OpenCL type.
LangAS getOpenCLTypeAddrSpace(const Type *T) const;
void setcudaConfigureCallDecl(FunctionDecl *FD) {
cudaConfigureCallDecl = FD;
}
FunctionDecl *getcudaConfigureCallDecl() {
return cudaConfigureCallDecl;
}
@ -1192,7 +1241,6 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// Returns true iff we need copy/dispose helpers for the given type.
bool BlockRequiresCopying(QualType Ty, const VarDecl *D);
/// Returns true, if given type has a known lifetime. HasByrefExtendedLayout is set
/// to false in this case. If HasByrefExtendedLayout returns true, byref variable
/// has extended lifetime.
@ -1269,6 +1317,10 @@ class ASTContext : public RefCountedBase<ASTContext> {
Expr *SizeExpr,
SourceLocation AttrLoc) const;
QualType getDependentAddressSpaceType(QualType PointeeType,
Expr *AddrSpaceExpr,
SourceLocation AttrLoc) const;
/// \brief Return a K&R style C function type like 'int()'.
QualType getFunctionNoProtoType(QualType ResultTy,
const FunctionType::ExtInfo &Info) const;
@ -1396,6 +1448,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
QualType Canonical = QualType()) const;
bool ObjCObjectAdoptsQTypeProtocols(QualType QT, ObjCInterfaceDecl *Decl);
/// QIdProtocolsAdoptObjCObjectProtocols - Checks that protocols in
/// QT's qualified-id protocol list adopt all protocols in IDecl's list
/// of protocols.
@ -1426,7 +1479,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// \brief C++11 deduction pattern for 'auto &&' type.
QualType getAutoRRefDeductType() const;
/// \brief C++1z deduced class template specialization type.
/// \brief C++17 deduced class template specialization type.
QualType getDeducedTemplateSpecializationType(TemplateName Template,
QualType DeducedType,
bool IsDependent) const;
@ -1488,6 +1541,11 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// <stddef.h>. Pointer - pointer requires this (C99 6.5.6p9).
QualType getPointerDiffType() const;
/// \brief Return the unique unsigned counterpart of "ptrdiff_t"
/// integer type. The standard (C11 7.21.6.1p7) refers to this type
/// in the definition of %tu format specifier.
QualType getUnsignedPointerDiffType() const;
/// \brief Return the unique type for "pid_t" defined in
/// <sys/types.h>. We need this to compute the correct type for vfork().
QualType getProcessIDType() const;
@ -1581,6 +1639,24 @@ class ASTContext : public RefCountedBase<ASTContext> {
return NSCopyingName;
}
CanQualType getNSUIntegerType() const {
assert(Target && "Expected target to be initialized");
const llvm::Triple &T = Target->getTriple();
// Windows is LLP64 rather than LP64
if (T.isOSWindows() && T.isArch64Bit())
return UnsignedLongLongTy;
return UnsignedLongTy;
}
CanQualType getNSIntegerType() const {
assert(Target && "Expected target to be initialized");
const llvm::Triple &T = Target->getTriple();
// Windows is LLP64 rather than LP64
if (T.isOSWindows() && T.isArch64Bit())
return LongLongTy;
return LongTy;
}
/// Retrieve the identifier 'bool'.
IdentifierInfo *getBoolName() const {
if (!BoolName)
@ -1865,10 +1941,17 @@ class ASTContext : public RefCountedBase<ASTContext> {
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>
/// No error
GE_None,
/// Missing a type from <stdio.h>
GE_Missing_stdio,
/// Missing a type from <setjmp.h>
GE_Missing_setjmp,
/// Missing a type from <ucontext.h>
GE_Missing_ucontext
};
/// \brief Return the type for the specified builtin.
@ -2019,7 +2102,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
getASTObjCImplementationLayout(const ObjCImplementationDecl *D) const;
/// \brief Get our current best idea for the key function of the
/// given record decl, or NULL if there isn't one.
/// given record decl, or nullptr if there isn't one.
///
/// The key function is, according to the Itanium C++ ABI section 5.2.3:
/// ...the first non-pure virtual function that is not inline at the
@ -2072,6 +2155,10 @@ class ASTContext : public RefCountedBase<ASTContext> {
void CollectInheritedProtocols(const Decl *CDecl,
llvm::SmallPtrSet<ObjCProtocolDecl*, 8> &Protocols);
/// \brief Return true if the specified type has unique object representations
/// according to (C++17 [meta.unary.prop]p9)
bool hasUniqueObjectRepresentations(QualType Ty) const;
//===--------------------------------------------------------------------===//
// Type Operators
//===--------------------------------------------------------------------===//
@ -2103,7 +2190,6 @@ class ASTContext : public RefCountedBase<ASTContext> {
bool hasSameType(QualType T1, QualType T2) const {
return getCanonicalType(T1) == getCanonicalType(T2);
}
bool hasSameType(const Type *T1, const Type *T2) const {
return getCanonicalType(T1) == getCanonicalType(T2);
}
@ -2192,7 +2278,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) const;
/// \brief Retrieves the default calling convention for the current target.
CallingConv getDefaultCallingConvention(bool isVariadic,
CallingConv getDefaultCallingConvention(bool IsVariadic,
bool IsCXXMethod) const;
/// \brief Retrieves the "canonical" template name that refers to a
@ -2326,14 +2412,14 @@ class ASTContext : public RefCountedBase<ASTContext> {
return getTargetAddressSpace(Q.getAddressSpace());
}
unsigned getTargetAddressSpace(unsigned AS) const;
unsigned getTargetAddressSpace(LangAS AS) const;
/// Get target-dependent integer value for null pointer which is used for
/// constant folding.
uint64_t getTargetNullPointerValue(QualType QT) const;
bool addressSpaceMapManglingFor(unsigned AS) const {
return AddrSpaceMapMangling || AS >= LangAS::FirstTargetAddressSpace;
bool addressSpaceMapManglingFor(LangAS AS) const {
return AddrSpaceMapMangling || isTargetAddressSpace(AS);
}
private:
@ -2355,12 +2441,15 @@ class ASTContext : public RefCountedBase<ASTContext> {
bool isObjCIdType(QualType T) const {
return T == getObjCIdType();
}
bool isObjCClassType(QualType T) const {
return T == getObjCClassType();
}
bool isObjCSelType(QualType T) const {
return T == getObjCSelType();
}
bool ObjCQualifiedIdTypesAreCompatible(QualType LHS, QualType RHS,
bool ForCompare);
@ -2394,9 +2483,30 @@ class ASTContext : public RefCountedBase<ASTContext> {
QualType mergeObjCGCQualifiers(QualType, QualType);
bool doFunctionTypesMatchOnExtParameterInfos(
const FunctionProtoType *FromFunctionType,
const FunctionProtoType *ToFunctionType);
/// This function merges the ExtParameterInfo lists of two functions. It
/// returns true if the lists are compatible. The merged list is returned in
/// NewParamInfos.
///
/// \param FirstFnType The type of the first function.
///
/// \param SecondFnType The type of the second function.
///
/// \param CanUseFirst This flag is set to true if the first function's
/// ExtParameterInfo list can be used as the composite list of
/// ExtParameterInfo.
///
/// \param CanUseSecond This flag is set to true if the second function's
/// ExtParameterInfo list can be used as the composite list of
/// ExtParameterInfo.
///
/// \param NewParamInfos The composite list of ExtParameterInfo. The list is
/// empty if none of the flags are set.
///
bool mergeExtParameterInfo(
const FunctionProtoType *FirstFnType,
const FunctionProtoType *SecondFnType,
bool &CanUseFirst, bool &CanUseSecond,
SmallVectorImpl<FunctionProtoType::ExtParameterInfo> &NewParamInfos);
void ResetObjCLayout(const ObjCContainerDecl *CD);
@ -2432,12 +2542,13 @@ class ASTContext : public RefCountedBase<ASTContext> {
bool isSentinelNullExpr(const Expr *E);
/// \brief Get the implementation of the ObjCInterfaceDecl \p D, or NULL if
/// \brief Get the implementation of the ObjCInterfaceDecl \p D, or nullptr if
/// none exists.
ObjCImplementationDecl *getObjCImplementation(ObjCInterfaceDecl *D);
/// \brief Get the implementation of the ObjCCategoryDecl \p D, or NULL if
/// \brief Get the implementation of the ObjCCategoryDecl \p D, or nullptr if
/// none exists.
ObjCCategoryImplDecl *getObjCImplementation(ObjCCategoryDecl *D);
ObjCCategoryImplDecl *getObjCImplementation(ObjCCategoryDecl *D);
/// \brief Return true if there is at least one \@implementation in the TU.
bool AnyObjCImplementation() {
@ -2447,6 +2558,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// \brief Set the implementation of ObjCInterfaceDecl.
void setObjCImplementation(ObjCInterfaceDecl *IFaceD,
ObjCImplementationDecl *ImplD);
/// \brief Set the implementation of ObjCCategoryDecl.
void setObjCImplementation(ObjCCategoryDecl *CatD,
ObjCCategoryImplDecl *ImplD);
@ -2466,8 +2578,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// \brief Set the copy inialization expression of a block var decl.
void setBlockVarCopyInits(VarDecl*VD, Expr* Init);
/// \brief Get the copy initialization expression of the VarDecl \p VD, or
/// NULL if none exists.
/// nullptr if none exists.
Expr *getBlockVarCopyInits(const VarDecl* VD);
/// \brief Allocate an uninitialized TypeSourceInfo.
@ -2636,6 +2749,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
const FieldDecl *Field,
bool includeVBases = true,
QualType *NotEncodedT=nullptr) const;
public:
// Adds the encoding of a method parameter or return type.
void getObjCEncodingForMethodParameter(Decl::ObjCDeclQualifier QT,
@ -2647,11 +2761,19 @@ class ASTContext : public RefCountedBase<ASTContext> {
bool isMSStaticDataMemberInlineDefinition(const VarDecl *VD) const;
enum class InlineVariableDefinitionKind {
None, ///< Not an inline variable.
Weak, ///< Weak definition of inline variable.
WeakUnknown, ///< Weak for now, might become strong later in this TU.
Strong ///< Strong definition.
/// Not an inline variable.
None,
/// Weak definition of inline variable.
Weak,
/// Weak for now, might become strong later in this TU.
WeakUnknown,
/// Strong definition.
Strong
};
/// \brief Determine whether a definition of this inline variable should
/// be treated as a weak or strong definition. For compatibility with
/// C++14 and before, for a constexpr static data member, if there is an
@ -2661,6 +2783,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
getInlineVariableDefinitionKind(const VarDecl *VD) const;
private:
friend class DeclarationNameTable;
friend class DeclContext;
const ASTRecordLayout &
getObjCLayout(const ObjCInterfaceDecl *D,
const ObjCImplementationDecl *Impl) const;
@ -2673,26 +2798,23 @@ class ASTContext : public RefCountedBase<ASTContext> {
// into the datastructures which avoids this mess during deallocation but is
// wasteful of memory, and here we require a lot of error prone book keeping
// in order to track and run destructors while we're tearing things down.
typedef llvm::SmallVector<std::pair<void (*)(void *), void *>, 16>
DeallocationFunctionsAndArguments;
using DeallocationFunctionsAndArguments =
llvm::SmallVector<std::pair<void (*)(void *), void *>, 16>;
DeallocationFunctionsAndArguments Deallocations;
// FIXME: This currently contains the set of StoredDeclMaps used
// by DeclContext objects. This probably should not be in ASTContext,
// but we include it here so that ASTContext can quickly deallocate them.
llvm::PointerIntPair<StoredDeclsMap*,1> LastSDM;
friend class DeclContext;
friend class DeclarationNameTable;
void ReleaseDeclContextMaps();
void ReleaseParentMapEntries();
llvm::PointerIntPair<StoredDeclsMap *, 1> LastSDM;
std::unique_ptr<ParentMapPointers> PointerParents;
std::unique_ptr<ParentMapOtherNodes> OtherParents;
std::unique_ptr<VTableContextBase> VTContext;
void ReleaseDeclContextMaps();
void ReleaseParentMapEntries();
public:
enum PragmaSectionFlag : unsigned {
PSF_None = 0,
@ -2712,27 +2834,26 @@ class ASTContext : public RefCountedBase<ASTContext> {
SectionInfo(DeclaratorDecl *Decl,
SourceLocation PragmaSectionLocation,
int SectionFlags)
: Decl(Decl),
PragmaSectionLocation(PragmaSectionLocation),
SectionFlags(SectionFlags) {}
: Decl(Decl), PragmaSectionLocation(PragmaSectionLocation),
SectionFlags(SectionFlags) {}
};
llvm::StringMap<SectionInfo> SectionInfos;
};
/// \brief Utility function for constructing a nullary selector.
static inline Selector GetNullarySelector(StringRef name, ASTContext& Ctx) {
inline Selector GetNullarySelector(StringRef name, ASTContext &Ctx) {
IdentifierInfo* II = &Ctx.Idents.get(name);
return Ctx.Selectors.getSelector(0, &II);
}
/// \brief Utility function for constructing an unary selector.
static inline Selector GetUnarySelector(StringRef name, ASTContext& Ctx) {
inline Selector GetUnarySelector(StringRef name, ASTContext &Ctx) {
IdentifierInfo* II = &Ctx.Idents.get(name);
return Ctx.Selectors.getSelector(1, &II);
}
} // end namespace clang
} // namespace clang
// operator new and delete aren't allowed inside namespaces.
@ -2763,11 +2884,12 @@ static inline Selector GetUnarySelector(StringRef name, ASTContext& Ctx) {
/// @param C The ASTContext that provides the allocator.
/// @param Alignment The alignment of the allocated memory (if the underlying
/// allocator supports it).
/// @return The allocated memory. Could be NULL.
/// @return The allocated memory. Could be nullptr.
inline void *operator new(size_t Bytes, const clang::ASTContext &C,
size_t Alignment) {
return C.Allocate(Bytes, Alignment);
}
/// @brief Placement delete companion to the new above.
///
/// This operator is just a companion to the new above. There is no way of
@ -2800,7 +2922,7 @@ inline void operator delete(void *Ptr, const clang::ASTContext &C, size_t) {
/// @param C The ASTContext that provides the allocator.
/// @param Alignment The alignment of the allocated memory (if the underlying
/// allocator supports it).
/// @return The allocated memory. Could be NULL.
/// @return The allocated memory. Could be nullptr.
inline void *operator new[](size_t Bytes, const clang::ASTContext& C,
size_t Alignment = 8) {
return C.Allocate(Bytes, Alignment);

View File

@ -22,6 +22,7 @@ namespace clang {
class CXXRecordDecl;
class Decl;
class DeclContext;
class Expr;
class FieldDecl;
class FunctionDecl;
class FunctionTemplateDecl;
@ -35,6 +36,7 @@ namespace clang {
class QualType;
class RecordDecl;
class TagDecl;
class ValueDecl;
class VarDecl;
class VarTemplateDecl;
class VarTemplateSpecializationDecl;
@ -80,13 +82,19 @@ class ASTMutationListener {
/// \brief A virtual destructor's operator delete has been resolved.
virtual void ResolvedOperatorDelete(const CXXDestructorDecl *DD,
const FunctionDecl *Delete) {}
const FunctionDecl *Delete,
Expr *ThisArg) {}
/// \brief An implicit member got a definition.
virtual void CompletedImplicitDefinition(const FunctionDecl *D) {}
/// \brief A static data member was implicitly instantiated.
virtual void StaticDataMemberInstantiated(const VarDecl *D) {}
/// \brief The instantiation of a templated function or variable was
/// requested. In particular, the point of instantiation and template
/// specialization kind of \p D may have changed.
virtual void InstantiationRequested(const ValueDecl *D) {}
/// \brief A templated variable's definition was implicitly instantiated.
virtual void VariableDefinitionInstantiated(const VarDecl *D) {}
/// \brief A function template's definition was instantiated.
virtual void FunctionDefinitionInstantiated(const FunctionDecl *D) {}

View File

@ -1,4 +1,4 @@
//===-- ASTUnresolvedSet.h - Unresolved sets of declarations ---*- C++ -*-===//
//===- ASTUnresolvedSet.h - Unresolved sets of declarations -----*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@ -16,14 +16,22 @@
#define LLVM_CLANG_AST_ASTUNRESOLVEDSET_H
#include "clang/AST/ASTVector.h"
#include "clang/AST/DeclAccessPair.h"
#include "clang/AST/UnresolvedSet.h"
#include "clang/Basic/Specifiers.h"
#include <cassert>
#include <cstdint>
namespace clang {
class NamedDecl;
/// \brief An UnresolvedSet-like class which uses the ASTContext's allocator.
class ASTUnresolvedSet {
friend class LazyASTUnresolvedSet;
struct DeclsTy : ASTVector<DeclAccessPair> {
DeclsTy() {}
DeclsTy() = default;
DeclsTy(ASTContext &C, unsigned N) : ASTVector<DeclAccessPair>(C, N) {}
bool isLazy() const { return getTag(); }
@ -32,14 +40,12 @@ class ASTUnresolvedSet {
DeclsTy Decls;
friend class LazyASTUnresolvedSet;
public:
ASTUnresolvedSet() {}
ASTUnresolvedSet() = default;
ASTUnresolvedSet(ASTContext &C, unsigned N) : Decls(C, N) {}
typedef UnresolvedSetIterator iterator;
typedef UnresolvedSetIterator const_iterator;
using iterator = UnresolvedSetIterator;
using const_iterator = UnresolvedSetIterator;
iterator begin() { return iterator(Decls.begin()); }
iterator end() { return iterator(Decls.end()); }
@ -98,13 +104,14 @@ class LazyASTUnresolvedSet {
}
void reserve(ASTContext &C, unsigned N) { Impl.reserve(C, N); }
void addLazyDecl(ASTContext &C, uintptr_t ID, AccessSpecifier AS) {
assert(Impl.empty() || Impl.Decls.isLazy());
Impl.Decls.setLazy(true);
Impl.addDecl(C, reinterpret_cast<NamedDecl*>(ID << 2), AS);
Impl.addDecl(C, reinterpret_cast<NamedDecl *>(ID << 2), AS);
}
};
} // namespace clang
#endif
#endif // LLVM_CLANG_AST_ASTUNRESOLVEDSET_H

View File

@ -1,4 +1,4 @@
//===- ASTVector.h - Vector that uses ASTContext for allocation --*- C++ -*-=//
//===- ASTVector.h - Vector that uses ASTContext for allocation ---*- C++ -*-=//
//
// The LLVM Compiler Infrastructure
//
@ -18,22 +18,26 @@
#ifndef LLVM_CLANG_AST_ASTVECTOR_H
#define LLVM_CLANG_AST_ASTVECTOR_H
#include "clang/AST/AttrIterator.h"
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/Support/type_traits.h"
#include <algorithm>
#include <cassert>
#include <cstddef>
#include <cstring>
#include <iterator>
#include <memory>
#include <type_traits>
#include <utility>
namespace clang {
class ASTContext;
class ASTContext;
template<typename T>
class ASTVector {
private:
T *Begin, *End;
llvm::PointerIntPair<T*, 1, bool> Capacity;
T *Begin = nullptr;
T *End = nullptr;
llvm::PointerIntPair<T *, 1, bool> Capacity;
void setEnd(T *P) { this->End = P; }
@ -45,7 +49,7 @@ class ASTVector {
public:
// Default ctor - Initialize to empty.
ASTVector() : Begin(nullptr), End(nullptr), Capacity(nullptr, false) {}
ASTVector() : Capacity(nullptr, false) {}
ASTVector(ASTVector &&O) : Begin(O.Begin), End(O.End), Capacity(O.Capacity) {
O.Begin = O.End = nullptr;
@ -53,14 +57,15 @@ class ASTVector {
O.Capacity.setInt(false);
}
ASTVector(const ASTContext &C, unsigned N)
: Begin(nullptr), End(nullptr), Capacity(nullptr, false) {
ASTVector(const ASTContext &C, unsigned N) : Capacity(nullptr, false) {
reserve(C, N);
}
ASTVector &operator=(ASTVector &&RHS) {
ASTVector O(std::move(RHS));
using std::swap;
swap(Begin, O.Begin);
swap(End, O.End);
swap(Capacity, O.Capacity);
@ -74,19 +79,19 @@ class ASTVector {
}
}
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef T value_type;
typedef T* iterator;
typedef const T* const_iterator;
using size_type = size_t;
using difference_type = ptrdiff_t;
using value_type = T;
using iterator = T *;
using const_iterator = const T *;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
typedef std::reverse_iterator<iterator> reverse_iterator;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
using reverse_iterator = std::reverse_iterator<iterator>;
typedef T& reference;
typedef const T& const_reference;
typedef T* pointer;
typedef const T* const_pointer;
using reference = T &;
using const_reference = const T &;
using pointer = T *;
using const_pointer = const T *;
// forward iterator creation methods.
iterator begin() { return Begin; }
@ -175,7 +180,6 @@ class ASTVector {
size_t capacity() const { return this->capacity_ptr() - Begin; }
/// append - Add the specified range to the end of the SmallVector.
///
template<typename in_iter>
void append(const ASTContext &C, in_iter in_start, in_iter in_end) {
size_type NumInputs = std::distance(in_start, in_end);
@ -195,7 +199,6 @@ class ASTVector {
}
/// append - Add the specified range to the end of the SmallVector.
///
void append(const ASTContext &C, size_type NumInputs, const T &Elt) {
// Grow allocated space if needed.
if (NumInputs > size_type(this->capacity_ptr()-this->end()))
@ -368,6 +371,7 @@ class ASTVector {
const_iterator capacity_ptr() const {
return (iterator) Capacity.getPointer();
}
iterator capacity_ptr() { return (iterator)Capacity.getPointer(); }
};
@ -401,5 +405,6 @@ void ASTVector<T>::grow(const ASTContext &C, size_t MinSize) {
Capacity.setPointer(Begin+NewCapacity);
}
} // end: clang namespace
#endif
} // namespace clang
#endif // LLVM_CLANG_AST_ASTVECTOR_H

View File

@ -1,4 +1,4 @@
//===--- AttrIterator.h - Classes for attribute iteration -------*- C++ -*-===//
//===- AttrIterator.h - Classes for attribute iteration ---------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@ -15,16 +15,23 @@
#define LLVM_CLANG_AST_ATTRITERATOR_H
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Casting.h"
#include <cassert>
#include <cstddef>
#include <iterator>
namespace clang {
class ASTContext;
class Attr;
}
class ASTContext;
class Attr;
} // namespace clang
// Defined in ASTContext.h
void *operator new(size_t Bytes, const clang::ASTContext &C,
size_t Alignment = 8);
// FIXME: Being forced to not have a default argument here due to redeclaration
// rules on default arguments sucks
void *operator new[](size_t Bytes, const clang::ASTContext &C,
@ -39,13 +46,13 @@ void operator delete[](void *Ptr, const clang::ASTContext &C, size_t);
namespace clang {
/// AttrVec - A vector of Attr, which is how they are stored on the AST.
typedef SmallVector<Attr *, 4> AttrVec;
using AttrVec = SmallVector<Attr *, 4>;
/// specific_attr_iterator - Iterates over a subrange of an AttrVec, only
/// providing attributes that are of a specific type.
template <typename SpecificAttr, typename Container = AttrVec>
class specific_attr_iterator {
typedef typename Container::const_iterator Iterator;
using Iterator = typename Container::const_iterator;
/// Current - The current, underlying iterator.
/// In order to ensure we don't dereference an invalid iterator unless
@ -67,14 +74,14 @@ class specific_attr_iterator {
}
public:
typedef SpecificAttr* value_type;
typedef SpecificAttr* reference;
typedef SpecificAttr* pointer;
typedef std::forward_iterator_tag iterator_category;
typedef std::ptrdiff_t difference_type;
using value_type = SpecificAttr *;
using reference = SpecificAttr *;
using pointer = SpecificAttr *;
using iterator_category = std::forward_iterator_tag;
using difference_type = std::ptrdiff_t;
specific_attr_iterator() : Current() { }
explicit specific_attr_iterator(Iterator i) : Current(i) { }
specific_attr_iterator() = default;
explicit specific_attr_iterator(Iterator i) : Current(i) {}
reference operator*() const {
AdvanceToNext();
@ -136,6 +143,6 @@ inline SpecificAttr *getSpecificAttr(const Container& container) {
return nullptr;
}
} // end namespace clang
} // namespace clang
#endif
#endif // LLVM_CLANG_AST_ATTRITERATOR_H

View File

@ -1,4 +1,4 @@
//===--- BaseSubobject.h - BaseSubobject class ----------------------------===//
//===- BaseSubobject.h - BaseSubobject class --------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@ -15,12 +15,15 @@
#define LLVM_CLANG_AST_BASESUBOBJECT_H
#include "clang/AST/CharUnits.h"
#include "clang/AST/DeclCXX.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/Support/DataTypes.h"
#include "llvm/ADT/DenseMapInfo.h"
#include "llvm/Support/type_traits.h"
#include <cstdint>
#include <utility>
namespace clang {
class CXXRecordDecl;
// BaseSubobject - Uniquely identifies a direct or indirect base class.
// Stores both the base class decl and the offset from the most derived class to
// the base class. Used for vtable and VTT generation.
@ -32,9 +35,9 @@ class BaseSubobject {
CharUnits BaseOffset;
public:
BaseSubobject() { }
BaseSubobject() = default;
BaseSubobject(const CXXRecordDecl *Base, CharUnits BaseOffset)
: Base(Base), BaseOffset(BaseOffset) { }
: Base(Base), BaseOffset(BaseOffset) {}
/// getBase - Returns the base class declaration.
const CXXRecordDecl *getBase() const { return Base; }
@ -47,7 +50,7 @@ class BaseSubobject {
}
};
} // end namespace clang
} // namespace clang
namespace llvm {
@ -65,7 +68,8 @@ template<> struct DenseMapInfo<clang::BaseSubobject> {
}
static unsigned getHashValue(const clang::BaseSubobject &Base) {
typedef std::pair<const clang::CXXRecordDecl *, clang::CharUnits> PairTy;
using PairTy = std::pair<const clang::CXXRecordDecl *, clang::CharUnits>;
return DenseMapInfo<PairTy>::getHashValue(PairTy(Base.getBase(),
Base.getBaseOffset()));
}
@ -81,6 +85,6 @@ template <> struct isPodLike<clang::BaseSubobject> {
static const bool value = true;
};
}
} // namespace llvm
#endif
#endif // LLVM_CLANG_AST_BASESUBOBJECT_H

View File

@ -133,6 +133,9 @@ FLOATING_TYPE(Double, DoubleTy)
// 'long double'
FLOATING_TYPE(LongDouble, LongDoubleTy)
// '_Float16'
FLOATING_TYPE(Float16, HalfTy)
// '__float128'
FLOATING_TYPE(Float128, Float128Ty)

View File

@ -50,3 +50,6 @@ clang_tablegen(CommentCommandList.inc -gen-clang-comment-command-list
SOURCE CommentCommands.td
TARGET ClangCommentCommandList)
clang_tablegen(StmtDataCollectors.inc -gen-clang-data-collectors
SOURCE StmtDataCollectors.td
TARGET StmtDataCollectors)

View File

@ -1,4 +1,4 @@
//===------ CXXInheritance.h - C++ Inheritance ------------------*- C++ -*-===//
//===- CXXInheritance.h - C++ Inheritance -----------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@ -16,19 +16,23 @@
#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclarationName.h"
#include "clang/AST/Type.h"
#include "clang/AST/TypeOrdering.h"
#include "clang/Basic/Specifiers.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallVector.h"
#include <cassert>
#include "llvm/ADT/iterator_range.h"
#include <list>
#include <memory>
#include <utility>
namespace clang {
class CXXBaseSpecifier;
class CXXMethodDecl;
class CXXRecordDecl;
class ASTContext;
class NamedDecl;
/// \brief Represents an element in a path from a derived class to a
@ -66,12 +70,12 @@ struct CXXBasePathElement {
/// subobject is being used.
class CXXBasePath : public SmallVector<CXXBasePathElement, 4> {
public:
CXXBasePath() : Access(AS_public) {}
/// \brief The access along this inheritance path. This is only
/// calculated when recording paths. AS_none is a special value
/// used to indicate a path which permits no legal access.
AccessSpecifier Access;
AccessSpecifier Access = AS_public;
CXXBasePath() = default;
/// \brief The set of declarations found inside this base class
/// subobject.
@ -113,8 +117,10 @@ class CXXBasePath : public SmallVector<CXXBasePathElement, 4> {
/// refer to the same base class subobject of type A (the virtual
/// one), there is no ambiguity.
class CXXBasePaths {
friend class CXXRecordDecl;
/// \brief The type from which this search originated.
CXXRecordDecl *Origin;
CXXRecordDecl *Origin = nullptr;
/// Paths - The actual set of paths that can be taken from the
/// derived class to the same base class.
@ -152,15 +158,13 @@ class CXXBasePaths {
CXXBasePath ScratchPath;
/// DetectedVirtual - The base class that is virtual.
const RecordType *DetectedVirtual;
const RecordType *DetectedVirtual = nullptr;
/// \brief Array of the declarations that have been found. This
/// array is constructed only if needed, e.g., to iterate over the
/// results within LookupResult.
std::unique_ptr<NamedDecl *[]> DeclsFound;
unsigned NumDeclsFound;
friend class CXXRecordDecl;
unsigned NumDeclsFound = 0;
void ComputeDeclsFound();
@ -169,17 +173,16 @@ class CXXBasePaths {
bool LookupInDependent = false);
public:
typedef std::list<CXXBasePath>::iterator paths_iterator;
typedef std::list<CXXBasePath>::const_iterator const_paths_iterator;
typedef NamedDecl **decl_iterator;
using paths_iterator = std::list<CXXBasePath>::iterator;
using const_paths_iterator = std::list<CXXBasePath>::const_iterator;
using decl_iterator = NamedDecl **;
/// BasePaths - Construct a new BasePaths structure to record the
/// paths for a derived-to-base search.
explicit CXXBasePaths(bool FindAmbiguities = true, bool RecordPaths = true,
bool DetectVirtual = true)
: Origin(), FindAmbiguities(FindAmbiguities), RecordPaths(RecordPaths),
DetectVirtual(DetectVirtual), DetectedVirtual(nullptr),
NumDeclsFound(0) {}
: FindAmbiguities(FindAmbiguities), RecordPaths(RecordPaths),
DetectVirtual(DetectVirtual) {}
paths_iterator begin() { return Paths.begin(); }
paths_iterator end() { return Paths.end(); }
@ -189,7 +192,8 @@ class CXXBasePaths {
CXXBasePath& front() { return Paths.front(); }
const CXXBasePath& front() const { return Paths.front(); }
typedef llvm::iterator_range<decl_iterator> decl_range;
using decl_range = llvm::iterator_range<decl_iterator>;
decl_range found_decls();
/// \brief Determine whether the path from the most-derived type to the
@ -231,25 +235,24 @@ class CXXBasePaths {
/// \brief Uniquely identifies a virtual method within a class
/// hierarchy by the method itself and a class subobject number.
struct UniqueVirtualMethod {
UniqueVirtualMethod()
: Method(nullptr), Subobject(0), InVirtualSubobject(nullptr) { }
UniqueVirtualMethod(CXXMethodDecl *Method, unsigned Subobject,
const CXXRecordDecl *InVirtualSubobject)
: Method(Method), Subobject(Subobject),
InVirtualSubobject(InVirtualSubobject) { }
/// \brief The overriding virtual method.
CXXMethodDecl *Method;
CXXMethodDecl *Method = nullptr;
/// \brief The subobject in which the overriding virtual method
/// resides.
unsigned Subobject;
unsigned Subobject = 0;
/// \brief The virtual base class subobject of which this overridden
/// virtual method is a part. Note that this records the closest
/// derived virtual base class subobject.
const CXXRecordDecl *InVirtualSubobject;
const CXXRecordDecl *InVirtualSubobject = nullptr;
UniqueVirtualMethod() = default;
UniqueVirtualMethod(CXXMethodDecl *Method, unsigned Subobject,
const CXXRecordDecl *InVirtualSubobject)
: Method(Method), Subobject(Subobject),
InVirtualSubobject(InVirtualSubobject) {}
friend bool operator==(const UniqueVirtualMethod &X,
const UniqueVirtualMethod &Y) {
@ -271,14 +274,16 @@ struct UniqueVirtualMethod {
/// pair is the virtual method that overrides it (including the
/// subobject in which that virtual function occurs).
class OverridingMethods {
typedef SmallVector<UniqueVirtualMethod, 4> ValuesT;
typedef llvm::MapVector<unsigned, ValuesT> MapType;
using ValuesT = SmallVector<UniqueVirtualMethod, 4>;
using MapType = llvm::MapVector<unsigned, ValuesT>;
MapType Overrides;
public:
// Iterate over the set of subobjects that have overriding methods.
typedef MapType::iterator iterator;
typedef MapType::const_iterator const_iterator;
using iterator = MapType::iterator;
using const_iterator = MapType::const_iterator;
iterator begin() { return Overrides.begin(); }
const_iterator begin() const { return Overrides.begin(); }
iterator end() { return Overrides.end(); }
@ -287,10 +292,10 @@ class OverridingMethods {
// Iterate over the set of overriding virtual methods in a given
// subobject.
typedef SmallVectorImpl<UniqueVirtualMethod>::iterator
overriding_iterator;
typedef SmallVectorImpl<UniqueVirtualMethod>::const_iterator
overriding_const_iterator;
using overriding_iterator =
SmallVectorImpl<UniqueVirtualMethod>::iterator;
using overriding_const_iterator =
SmallVectorImpl<UniqueVirtualMethod>::const_iterator;
// Add a new overriding method for a particular subobject.
void add(unsigned OverriddenSubobject, UniqueVirtualMethod Overriding);
@ -357,12 +362,12 @@ class OverridingMethods {
/// subobject numbers greater than 0 refer to non-virtual base class
/// subobjects of that type.
class CXXFinalOverriderMap
: public llvm::MapVector<const CXXMethodDecl *, OverridingMethods> { };
: public llvm::MapVector<const CXXMethodDecl *, OverridingMethods> {};
/// \brief A set of all the primary bases for a class.
class CXXIndirectPrimaryBaseSet
: public llvm::SmallSet<const CXXRecordDecl*, 32> { };
: public llvm::SmallSet<const CXXRecordDecl*, 32> {};
} // end namespace clang
} // namespace clang
#endif
#endif // LLVM_CLANG_AST_CXXINHERITANCE_H

View File

@ -1,4 +1,4 @@
//===-- CanonicalType.h - C Language Family Type Representation -*- C++ -*-===//
//===- CanonicalType.h - C Language Family Type Representation --*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@ -16,13 +16,29 @@
#define LLVM_CLANG_AST_CANONICALTYPE_H
#include "clang/AST/Type.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/iterator.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/PointerLikeTypeTraits.h"
#include <cassert>
#include <iterator>
#include <type_traits>
namespace clang {
template<typename T> class CanProxy;
template<typename T> struct CanProxyAdaptor;
class CXXRecordDecl;
class EnumDecl;
class Expr;
class IdentifierInfo;
class ObjCInterfaceDecl;
class RecordDecl;
class TagDecl;
class TemplateTypeParmDecl;
//----------------------------------------------------------------------------//
// Canonical, qualified type template
@ -46,8 +62,6 @@ template<typename T> struct CanProxyAdaptor;
/// converted to @c CanQual<ReferenceType>. Note that any @c CanQual type can
/// be implicitly converted to a QualType, but the reverse operation requires
/// a call to ASTContext::getCanonicalType().
///
///
template<typename T = Type>
class CanQual {
/// \brief The actual, canonical type.
@ -55,7 +69,7 @@ class CanQual {
public:
/// \brief Constructs a NULL canonical type.
CanQual() : Stored() { }
CanQual() = default;
/// \brief Converting constructor that permits implicit upcasting of
/// canonical type pointers.
@ -66,12 +80,11 @@ class CanQual {
/// \brief Retrieve the underlying type pointer, which refers to a
/// canonical type.
///
/// The underlying pointer must not be NULL.
/// The underlying pointer must not be nullptr.
const T *getTypePtr() const { return cast<T>(Stored.getTypePtr()); }
/// \brief Retrieve the underlying type pointer, which refers to a
/// canonical type, or NULL.
///
/// canonical type, or nullptr.
const T *getTypePtrOrNull() const {
return cast_or_null<T>(Stored.getTypePtrOrNull());
}
@ -125,9 +138,11 @@ class CanQual {
bool isConstQualified() const {
return Stored.isLocalConstQualified();
}
bool isVolatileQualified() const {
return Stored.isLocalVolatileQualified();
}
bool isRestrictQualified() const {
return Stored.isLocalRestrictQualified();
}
@ -195,7 +210,7 @@ inline bool operator!=(CanQual<T> x, CanQual<U> y) {
}
/// \brief Represents a canonical, potentially-qualified type.
typedef CanQual<Type> CanQualType;
using CanQualType = CanQual<Type>;
inline CanQualType Type::getCanonicalTypeUnqualified() const {
return CanQualType::CreateUnsafe(getCanonicalTypeInternal());
@ -320,7 +335,7 @@ class CanProxyBase {
/// than the more typical @c QualType, to propagate the notion of "canonical"
/// through the system.
template<typename T>
struct CanProxyAdaptor : CanProxyBase<T> { };
struct CanProxyAdaptor : CanProxyBase<T> {};
/// \brief Canonical proxy type returned when retrieving the members of a
/// canonical type or as the result of the @c CanQual<T>::getAs member
@ -333,7 +348,7 @@ template<typename T>
class CanProxy : public CanProxyAdaptor<T> {
public:
/// \brief Build a NULL proxy.
CanProxy() { }
CanProxy() = default;
/// \brief Build a proxy to the given canonical type.
CanProxy(CanQual<T> Stored) { this->Stored = Stored; }
@ -342,7 +357,7 @@ class CanProxy : public CanProxyAdaptor<T> {
operator CanQual<T>() const { return this->Stored; }
};
} // end namespace clang
} // namespace clang
namespace llvm {
@ -350,8 +365,9 @@ namespace llvm {
/// CanQual<T> to a specific Type class. We're prefer isa/dyn_cast/cast/etc.
/// to return smart pointer (proxies?).
template<typename T>
struct simplify_type< ::clang::CanQual<T> > {
typedef const T *SimpleType;
struct simplify_type< ::clang::CanQual<T>> {
using SimpleType = const T *;
static SimpleType getSimplifiedValue(::clang::CanQual<T> Val) {
return Val.getTypePtr();
}
@ -359,19 +375,20 @@ struct simplify_type< ::clang::CanQual<T> > {
// Teach SmallPtrSet that CanQual<T> is "basically a pointer".
template<typename T>
class PointerLikeTypeTraits<clang::CanQual<T> > {
public:
static inline void *getAsVoidPointer(clang::CanQual<T> P) {
struct PointerLikeTypeTraits<clang::CanQual<T>> {
static void *getAsVoidPointer(clang::CanQual<T> P) {
return P.getAsOpaquePtr();
}
static inline clang::CanQual<T> getFromVoidPointer(void *P) {
static clang::CanQual<T> getFromVoidPointer(void *P) {
return clang::CanQual<T>::getFromOpaquePtr(P);
}
// qualifier information is encoded in the low bits.
enum { NumLowBitsAvailable = 0 };
};
} // end namespace llvm
} // namespace llvm
namespace clang {
@ -389,7 +406,7 @@ struct CanTypeIterator
CanQualType,
typename std::iterator_traits<InputIterator>::difference_type,
CanProxy<Type>, CanQualType> {
CanTypeIterator() {}
CanTypeIterator() = default;
explicit CanTypeIterator(InputIterator Iter)
: CanTypeIterator::iterator_adaptor_base(std::move(Iter)) {}
@ -487,6 +504,7 @@ struct CanProxyAdaptor<FunctionProtoType>
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, hasExtParameterInfos)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(
ArrayRef<FunctionProtoType::ExtParameterInfo>, getExtParameterInfos)
CanQualType getParamType(unsigned i) const {
return CanQualType::CreateUnsafe(this->getTypePtr()->getParamType(i));
}
@ -494,8 +512,8 @@ struct CanProxyAdaptor<FunctionProtoType>
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isVariadic)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getTypeQuals)
typedef CanTypeIterator<FunctionProtoType::param_type_iterator>
param_type_iterator;
using param_type_iterator =
CanTypeIterator<FunctionProtoType::param_type_iterator>;
param_type_iterator param_type_begin() const {
return param_type_iterator(this->getTypePtr()->param_type_begin());
@ -567,7 +585,8 @@ struct CanProxyAdaptor<ObjCObjectType>
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isObjCQualifiedId)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isObjCQualifiedClass)
typedef ObjCObjectPointerType::qual_iterator qual_iterator;
using qual_iterator = ObjCObjectPointerType::qual_iterator;
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(qual_iterator, qual_begin)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(qual_iterator, qual_end)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, qual_empty)
@ -585,7 +604,8 @@ struct CanProxyAdaptor<ObjCObjectPointerType>
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isObjCQualifiedIdType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isObjCQualifiedClassType)
typedef ObjCObjectPointerType::qual_iterator qual_iterator;
using qual_iterator = ObjCObjectPointerType::qual_iterator;
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(qual_iterator, qual_begin)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(qual_iterator, qual_end)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, qual_empty)
@ -662,7 +682,6 @@ CanProxy<Type> CanTypeIterator<InputIterator>::operator->() const {
return CanProxy<Type>(*this);
}
}
} // namespace clang
#endif
#endif // LLVM_CLANG_AST_CANONICALTYPE_H

View File

@ -40,14 +40,14 @@ namespace clang {
typedef int64_t QuantityType;
private:
QuantityType Quantity;
QuantityType Quantity = 0;
explicit CharUnits(QuantityType C) : Quantity(C) {}
public:
/// CharUnits - A default constructor.
CharUnits() : Quantity(0) {}
CharUnits() = default;
/// Zero - Construct a CharUnits quantity of zero.
static CharUnits Zero() {

View File

@ -1,4 +1,4 @@
//===--- CommentVisitor.h - Visitor for Comment subclasses ------*- C++ -*-===//
//===- CommentVisitor.h - Visitor for Comment subclasses --------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@ -16,8 +16,8 @@
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 <typename T> struct make_ptr { using type = T *; };
template <typename T> struct make_const_ptr { using type = const T *; };
template<template <typename> class Ptr, typename ImplClass, typename RetTy=void>
class CommentVisitorBase {
@ -64,7 +64,7 @@ template<typename ImplClass, typename RetTy=void>
class ConstCommentVisitor :
public CommentVisitorBase<make_const_ptr, ImplClass, RetTy> {};
} // end namespace comments
} // end namespace clang
} // namespace comments
} // namespace clang
#endif
#endif // LLVM_CLANG_AST_COMMENTVISITOR_H

View File

@ -0,0 +1,65 @@
//===--- DatatCollection.h --------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
/// \file
/// \brief This file declares helper methods for collecting data from AST nodes.
///
/// To collect data from Stmt nodes, subclass ConstStmtVisitor and include
/// StmtDataCollectors.inc after defining the macros that you need. This
/// provides data collection implementations for most Stmt kinds. Note
/// that that code requires some conditions to be met:
///
/// - There must be a method addData(const T &Data) that accepts strings,
/// integral types as well as QualType. All data is forwarded using
/// to this method.
/// - The ASTContext of the Stmt must be accessible by the name Context.
///
/// It is also possible to override individual visit methods. Have a look at
/// the DataCollector in lib/Analysis/CloneDetection.cpp for a usage example.
///
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_AST_DATACOLLECTION_H
#define LLVM_CLANG_AST_DATACOLLECTION_H
#include "clang/AST/ASTContext.h"
namespace clang {
namespace data_collection {
/// Returns a string that represents all macro expansions that expanded into the
/// given SourceLocation.
///
/// If 'getMacroStack(A) == getMacroStack(B)' is true, then the SourceLocations
/// A and B are expanded from the same macros in the same order.
std::string getMacroStack(SourceLocation Loc, ASTContext &Context);
/// Utility functions for implementing addData() for a consumer that has a
/// method update(StringRef)
template <class T>
void addDataToConsumer(T &DataConsumer, llvm::StringRef Str) {
DataConsumer.update(Str);
}
template <class T> void addDataToConsumer(T &DataConsumer, const QualType &QT) {
addDataToConsumer(DataConsumer, QT.getAsString());
}
template <class T, class Type>
typename std::enable_if<
std::is_integral<Type>::value || std::is_enum<Type>::value ||
std::is_convertible<Type, size_t>::value // for llvm::hash_code
>::type
addDataToConsumer(T &DataConsumer, Type Data) {
DataConsumer.update(StringRef(reinterpret_cast<char *>(&Data), sizeof(Data)));
}
} // end namespace data_collection
} // end namespace clang
#endif // LLVM_CLANG_AST_DATACOLLECTION_H

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
//===-- DeclBase.h - Base Classes for representing declarations -*- C++ -*-===//
//===- DeclBase.h - Base Classes for representing declarations --*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@ -16,33 +16,40 @@
#include "clang/AST/AttrIterator.h"
#include "clang/AST/DeclarationName.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/Specifiers.h"
#include "clang/Basic/VersionTuple.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/iterator.h"
#include "llvm/ADT/iterator_range.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/PrettyStackTrace.h"
#include <algorithm>
#include <cassert>
#include <cstddef>
#include <iterator>
#include <string>
#include <type_traits>
#include <utility>
namespace clang {
class ASTContext;
class ASTMutationListener;
class BlockDecl;
class CXXRecordDecl;
class CompoundStmt;
class Attr;
class DeclContext;
class DeclarationName;
class DependentDiagnostic;
class EnumDecl;
class ExportDecl;
class ExternalSourceSymbolAttr;
class FunctionDecl;
class FunctionType;
class IdentifierInfo;
enum Linkage : unsigned char;
class LinkageComputer;
class LinkageSpecDecl;
class Module;
class NamedDecl;
class NamespaceDecl;
class ObjCCategoryDecl;
class ObjCCategoryImplDecl;
class ObjCContainerDecl;
@ -53,23 +60,21 @@ class ObjCMethodDecl;
class ObjCProtocolDecl;
struct PrintingPolicy;
class RecordDecl;
class SourceManager;
class Stmt;
class StoredDeclsMap;
class TemplateDecl;
class TranslationUnitDecl;
class UsingDirectiveDecl;
}
namespace clang {
/// \brief Captures the result of checking the availability of a
/// declaration.
enum AvailabilityResult {
AR_Available = 0,
AR_NotYetIntroduced,
AR_Deprecated,
AR_Unavailable
};
/// \brief Captures the result of checking the availability of a
/// declaration.
enum AvailabilityResult {
AR_Available = 0,
AR_NotYetIntroduced,
AR_Deprecated,
AR_Unavailable
};
/// Decl - This represents one declaration (or definition), e.g. a variable,
/// typedef, function, struct, etc.
@ -94,7 +99,7 @@ class LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) Decl {
/// \brief A placeholder type used to construct an empty shell of a
/// decl-derived type that will be filled in later (e.g., by some
/// deserialization method).
struct EmptyShell { };
struct EmptyShell {};
/// IdentifierNamespace - The different namespaces in which
/// declarations may appear. According to C99 6.2.3, there are
@ -208,15 +213,18 @@ class LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) Decl {
enum class ModuleOwnershipKind : unsigned {
/// This declaration is not owned by a module.
Unowned,
/// This declaration has an owning module, but is globally visible
/// (typically because its owning module is visible and we know that
/// modules cannot later become hidden in this compilation).
/// After serialization and deserialization, this will be converted
/// to VisibleWhenImported.
Visible,
/// This declaration has an owning module, and is visible when that
/// module is imported.
VisibleWhenImported,
/// This declaration has an owning module, but is only visible to
/// lookups that occur within that module.
ModulePrivate
@ -238,7 +246,6 @@ class LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) Decl {
DeclContext *LexicalDC;
};
/// DeclCtx - Holds either a DeclContext* or a MultipleDC*.
/// For declarations that don't contain C++ scope specifiers, it contains
/// the DeclContext where the Decl was declared.
@ -254,12 +261,14 @@ class LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) Decl {
/// // LexicalDC == global namespace
llvm::PointerUnion<DeclContext*, MultipleDC*> DeclCtx;
inline bool isInSemaDC() const { return DeclCtx.is<DeclContext*>(); }
inline bool isOutOfSemaDC() const { return DeclCtx.is<MultipleDC*>(); }
inline MultipleDC *getMultipleDC() const {
bool isInSemaDC() const { return DeclCtx.is<DeclContext*>(); }
bool isOutOfSemaDC() const { return DeclCtx.is<MultipleDC*>(); }
MultipleDC *getMultipleDC() const {
return DeclCtx.get<MultipleDC*>();
}
inline DeclContext *getSemanticDC() const {
DeclContext *getSemanticDC() const {
return DeclCtx.get<DeclContext*>();
}
@ -298,10 +307,16 @@ class LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) Decl {
static bool StatisticsEnabled;
protected:
friend class ASTDeclReader;
friend class ASTDeclWriter;
friend class ASTReader;
friend class CXXClassMemberWrapper;
friend class LinkageComputer;
template<typename decl_type> friend class Redeclarable;
/// Access - Used by C++ decls for the access specifier.
// NOTE: VC++ treats enums as signed, avoid using the AccessSpecifier enum
unsigned Access : 2;
friend class CXXClassMemberWrapper;
/// \brief Whether this declaration was loaded from an AST file.
unsigned FromASTFile : 1;
@ -313,13 +328,6 @@ class LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) Decl {
/// Otherwise, it is the linkage + 1.
mutable unsigned CacheValidAndLinkage : 3;
friend class ASTDeclWriter;
friend class ASTDeclReader;
friend class ASTReader;
friend class LinkageComputer;
template<typename decl_type> friend class Redeclarable;
/// \brief Allocate memory for a deserialized declaration.
///
/// This routine must be used to allocate memory for any declaration that is
@ -357,7 +365,7 @@ class LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) Decl {
protected:
Decl(Kind DK, DeclContext *DC, SourceLocation L)
: NextInContextAndBits(nullptr, getModuleOwnershipKindForChildOf(DC)),
DeclCtx(DC), Loc(L), DeclKind(DK), InvalidDecl(0), HasAttrs(false),
DeclCtx(DC), Loc(L), DeclKind(DK), InvalidDecl(false), HasAttrs(false),
Implicit(false), Used(false), Referenced(false),
TopLevelDeclInObjCContainer(false), Access(AS_none), FromASTFile(0),
IdentifierNamespace(getIdentifierNamespaceForKind(DK)),
@ -366,9 +374,9 @@ class LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) Decl {
}
Decl(Kind DK, EmptyShell Empty)
: NextInContextAndBits(), DeclKind(DK), InvalidDecl(0), HasAttrs(false),
Implicit(false), Used(false), Referenced(false),
TopLevelDeclInObjCContainer(false), Access(AS_none), FromASTFile(0),
: DeclKind(DK), InvalidDecl(false), HasAttrs(false), Implicit(false),
Used(false), Referenced(false), TopLevelDeclInObjCContainer(false),
Access(AS_none), FromASTFile(0),
IdentifierNamespace(getIdentifierNamespaceForKind(DK)),
CacheValidAndLinkage(0) {
if (StatisticsEnabled) add(DK);
@ -392,14 +400,15 @@ class LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) Decl {
}
public:
/// \brief Source range that this declaration covers.
virtual SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(getLocation(), getLocation());
}
SourceLocation getLocStart() const LLVM_READONLY {
return getSourceRange().getBegin();
}
SourceLocation getLocEnd() const LLVM_READONLY {
return getSourceRange().getEnd();
}
@ -460,12 +469,15 @@ class LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) Decl {
}
bool hasAttrs() const { return HasAttrs; }
void setAttrs(const AttrVec& Attrs) {
return setAttrsImpl(Attrs, getASTContext());
}
AttrVec &getAttrs() {
return const_cast<AttrVec&>(const_cast<const Decl*>(this)->getAttrs());
}
const AttrVec &getAttrs() const;
void dropAttrs();
@ -476,8 +488,8 @@ class LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) Decl {
setAttrs(AttrVec(1, A));
}
typedef AttrVec::const_iterator attr_iterator;
typedef llvm::iterator_range<attr_iterator> attr_range;
using attr_iterator = AttrVec::const_iterator;
using attr_range = llvm::iterator_range<attr_iterator>;
attr_range attrs() const {
return attr_range(attr_begin(), attr_end());
@ -510,6 +522,7 @@ class LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) Decl {
specific_attr_iterator<T> specific_attr_begin() const {
return specific_attr_iterator<T>(attr_begin());
}
template <typename T>
specific_attr_iterator<T> specific_attr_end() const {
return specific_attr_iterator<T>(attr_end());
@ -518,6 +531,7 @@ class LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) Decl {
template<typename T> T *getAttr() const {
return hasAttrs() ? getSpecificAttr<T>(getAttrs()) : nullptr;
}
template<typename T> bool hasAttr() const {
return hasAttrs() && hasSpecificAttr<T>(getAttrs());
}
@ -616,7 +630,6 @@ class LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) Decl {
}
public:
/// \brief Determine the availability of the given declaration.
///
/// This routine will determine the most restrictive availability of
@ -698,6 +711,7 @@ class LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) Decl {
private:
Module *getOwningModuleSlow() const;
protected:
bool hasLocalOwningModuleStorage() const;
@ -733,11 +747,18 @@ class LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) Decl {
return getModuleOwnershipKind() != ModuleOwnershipKind::Unowned;
}
/// Get the module that owns this declaration.
/// Get the module that owns this declaration (for visibility purposes).
Module *getOwningModule() const {
return isFromASTFile() ? getImportedOwningModule() : getLocalOwningModule();
}
/// Get the module that owns this declaration for linkage purposes.
/// There only ever is such a module under the C++ Modules TS.
///
/// \param IgnoreLinkage Ignore the linkage of the entity; assume that
/// all declarations in a global module fragment are unowned.
Module *getOwningModuleForLinkage(bool IgnoreLinkage = false) const;
/// \brief Determine whether this declaration might be hidden from name
/// lookup. Note that the declaration might be visible even if this returns
/// \c false, if the owning module is visible within the query context.
@ -770,14 +791,17 @@ class LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) Decl {
unsigned getIdentifierNamespace() const {
return IdentifierNamespace;
}
bool isInIdentifierNamespace(unsigned NS) const {
return getIdentifierNamespace() & NS;
}
static unsigned getIdentifierNamespaceForKind(Kind DK);
bool hasTagIdentifierNamespace() const {
return isTagIdentifierNamespace(getIdentifierNamespace());
}
static bool isTagIdentifierNamespace(unsigned NS) {
// TagDecls have Tag and Type set and may also have TagFriend.
return (NS & ~IDNS_TagFriend) == (IDNS_Tag | IDNS_Type);
@ -865,18 +889,18 @@ class LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) Decl {
/// \brief Iterates through all the redeclarations of the same decl.
class redecl_iterator {
/// Current - The current declaration.
Decl *Current;
Decl *Current = nullptr;
Decl *Starter;
public:
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;
using value_type = Decl *;
using reference = const value_type &;
using pointer = const value_type *;
using iterator_category = std::forward_iterator_tag;
using difference_type = std::ptrdiff_t;
redecl_iterator() : Current(nullptr) { }
explicit redecl_iterator(Decl *C) : Current(C), Starter(C) { }
redecl_iterator() = default;
explicit redecl_iterator(Decl *C) : Current(C), Starter(C) {}
reference operator*() const { return Current; }
value_type operator->() const { return Current; }
@ -899,12 +923,13 @@ class LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) Decl {
friend bool operator==(redecl_iterator x, redecl_iterator y) {
return x.Current == y.Current;
}
friend bool operator!=(redecl_iterator x, redecl_iterator y) {
return x.Current != y.Current;
}
};
typedef llvm::iterator_range<redecl_iterator> redecl_range;
using redecl_range = llvm::iterator_range<redecl_iterator>;
/// \brief Returns an iterator range for all the redeclarations of the same
/// decl. It will iterate at least once (when this decl is the only one).
@ -915,6 +940,7 @@ class LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) Decl {
redecl_iterator redecls_begin() const {
return redecl_iterator(const_cast<Decl *>(this));
}
redecl_iterator redecls_end() const { return redecl_iterator(); }
/// \brief Retrieve the previous declaration that declares the same entity
@ -1002,13 +1028,15 @@ class LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) Decl {
/// declaration, but in the semantic context of the enclosing namespace
/// scope.
void setLocalExternDecl() {
assert((IdentifierNamespace == IDNS_Ordinary ||
IdentifierNamespace == IDNS_OrdinaryFriend) &&
"namespace is not ordinary");
Decl *Prev = getPreviousDecl();
IdentifierNamespace &= ~IDNS_Ordinary;
// It's OK for the declaration to still have the "invisible friend" flag or
// the "conflicts with tag declarations in this scope" flag for the outer
// scope.
assert((IdentifierNamespace & ~(IDNS_OrdinaryFriend | IDNS_Tag)) == 0 &&
"namespace is not ordinary");
IdentifierNamespace |= IDNS_LocalExtern;
if (Prev && Prev->getIdentifierNamespace() & IDNS_Ordinary)
IdentifierNamespace |= IDNS_Ordinary;
@ -1094,10 +1122,13 @@ class LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) Decl {
static void printGroup(Decl** Begin, unsigned NumDecls,
raw_ostream &Out, const PrintingPolicy &Policy,
unsigned Indentation = 0);
// Debuggers don't usually respect default arguments.
void dump() const;
// Same as dump(), but forces color printing.
void dumpColor() const;
void dump(raw_ostream &Out, bool Deserialize = false) const;
/// \brief Looks through the Decl's underlying type to extract a FunctionType
@ -1132,10 +1163,11 @@ class PrettyStackTraceDecl : public llvm::PrettyStackTraceEntry {
SourceLocation Loc;
SourceManager &SM;
const char *Message;
public:
PrettyStackTraceDecl(const Decl *theDecl, SourceLocation L,
SourceManager &sm, const char *Msg)
: TheDecl(theDecl), Loc(L), SM(sm), Message(Msg) {}
: TheDecl(theDecl), Loc(L), SM(sm), Message(Msg) {}
void print(raw_ostream &OS) const override;
};
@ -1144,30 +1176,35 @@ class PrettyStackTraceDecl : public llvm::PrettyStackTraceEntry {
/// single result (with no stable storage) or a collection of results (with
/// stable storage provided by the lookup table).
class DeclContextLookupResult {
typedef ArrayRef<NamedDecl *> ResultTy;
using ResultTy = ArrayRef<NamedDecl *>;
ResultTy Result;
// If there is only one lookup result, it would be invalidated by
// reallocations of the name table, so store it separately.
NamedDecl *Single;
NamedDecl *Single = nullptr;
static NamedDecl *const SingleElementDummyList;
public:
DeclContextLookupResult() : Result(), Single() {}
DeclContextLookupResult() = default;
DeclContextLookupResult(ArrayRef<NamedDecl *> Result)
: Result(Result), Single() {}
: Result(Result) {}
DeclContextLookupResult(NamedDecl *Single)
: Result(SingleElementDummyList), Single(Single) {}
class iterator;
typedef llvm::iterator_adaptor_base<iterator, ResultTy::iterator,
std::random_access_iterator_tag,
NamedDecl *const> IteratorBase;
using IteratorBase =
llvm::iterator_adaptor_base<iterator, ResultTy::iterator,
std::random_access_iterator_tag,
NamedDecl *const>;
class iterator : public IteratorBase {
value_type SingleElement;
public:
iterator() : IteratorBase(), SingleElement() {}
iterator() = default;
explicit iterator(pointer Pos, value_type Single = nullptr)
: IteratorBase(Pos), SingleElement(Single) {}
@ -1175,9 +1212,10 @@ class DeclContextLookupResult {
return SingleElement ? SingleElement : IteratorBase::operator*();
}
};
typedef iterator const_iterator;
typedef iterator::pointer pointer;
typedef iterator::reference reference;
using const_iterator = iterator;
using pointer = iterator::pointer;
using reference = iterator::reference;
iterator begin() const { return iterator(Result.begin(), Single); }
iterator end() const { return iterator(Result.end(), Single); }
@ -1211,7 +1249,6 @@ class DeclContextLookupResult {
/// ExportDecl
/// BlockDecl
/// OMPDeclareReductionDecl
///
class DeclContext {
/// DeclKind - This indicates which class this is.
unsigned DeclKind : 8;
@ -1251,22 +1288,22 @@ class DeclContext {
/// contains an entry for a DeclarationName (and we haven't lazily
/// omitted anything), then it contains all relevant entries for that
/// name (modulo the hasExternalDecls() flag).
mutable StoredDeclsMap *LookupPtr;
mutable StoredDeclsMap *LookupPtr = nullptr;
protected:
friend class ASTDeclReader;
friend class ASTWriter;
friend class ExternalASTSource;
/// FirstDecl - The first declaration stored within this declaration
/// context.
mutable Decl *FirstDecl;
mutable Decl *FirstDecl = nullptr;
/// LastDecl - The last declaration stored within this declaration
/// context. FIXME: We could probably cache this value somewhere
/// outside of the DeclContext, to reduce the size of DeclContext by
/// another pointer.
mutable Decl *LastDecl;
friend class ExternalASTSource;
friend class ASTDeclReader;
friend class ASTWriter;
mutable Decl *LastDecl = nullptr;
/// \brief Build up a chain of declarations.
///
@ -1279,8 +1316,7 @@ class DeclContext {
ExternalVisibleStorage(false),
NeedToReconcileExternalVisibleStorage(false),
HasLazyLocalLexicalLookups(false), HasLazyExternalLexicalLookups(false),
UseQualifiedLookup(false),
LookupPtr(nullptr), FirstDecl(nullptr), LastDecl(nullptr) {}
UseQualifiedLookup(false) {}
public:
~DeclContext();
@ -1288,6 +1324,7 @@ class DeclContext {
Decl::Kind getDeclKind() const {
return static_cast<Decl::Kind>(DeclKind);
}
const char *getDeclKindName() const;
/// getParent - Returns the containing DeclContext.
@ -1495,19 +1532,20 @@ class DeclContext {
/// within this context.
class decl_iterator {
/// Current - The current declaration.
Decl *Current;
Decl *Current = nullptr;
public:
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;
using value_type = Decl *;
using reference = const value_type &;
using pointer = const value_type *;
using iterator_category = std::forward_iterator_tag;
using difference_type = std::ptrdiff_t;
decl_iterator() : Current(nullptr) { }
explicit decl_iterator(Decl *C) : Current(C) { }
decl_iterator() = default;
explicit decl_iterator(Decl *C) : Current(C) {}
reference operator*() const { return Current; }
// This doesn't meet the iterator requirements, but it's convenient
value_type operator->() const { return Current; }
@ -1525,12 +1563,13 @@ class DeclContext {
friend bool operator==(decl_iterator x, decl_iterator y) {
return x.Current == y.Current;
}
friend bool operator!=(decl_iterator x, decl_iterator y) {
return x.Current != y.Current;
}
};
typedef llvm::iterator_range<decl_iterator> decl_range;
using decl_range = llvm::iterator_range<decl_iterator>;
/// decls_begin/decls_end - Iterate over the declarations stored in
/// this context.
@ -1569,16 +1608,16 @@ class DeclContext {
}
public:
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;
using value_type = SpecificDecl *;
// TODO: Add reference and pointer types (with some appropriate proxy type)
// if we ever have a need for them.
using reference = void;
using pointer = void;
using difference_type =
std::iterator_traits<DeclContext::decl_iterator>::difference_type;
using iterator_category = std::forward_iterator_tag;
specific_decl_iterator() : Current() { }
specific_decl_iterator() = default;
/// specific_decl_iterator - Construct a new iterator over a
/// subset of the declarations the range [C,
@ -1593,6 +1632,7 @@ class DeclContext {
}
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; }
@ -1646,16 +1686,16 @@ class DeclContext {
}
public:
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;
using value_type = SpecificDecl *;
// TODO: Add reference and pointer types (with some appropriate proxy type)
// if we ever have a need for them.
using reference = void;
using pointer = void;
using difference_type =
std::iterator_traits<DeclContext::decl_iterator>::difference_type;
using iterator_category = std::forward_iterator_tag;
filtered_decl_iterator() : Current() { }
filtered_decl_iterator() = default;
/// filtered_decl_iterator - Construct a new iterator over a
/// subset of the declarations the range [C,
@ -1733,8 +1773,8 @@ class DeclContext {
/// @brief Checks whether a declaration is in this context.
bool containsDecl(Decl *D) const;
typedef DeclContextLookupResult lookup_result;
typedef lookup_result::iterator lookup_iterator;
using lookup_result = DeclContextLookupResult;
using lookup_iterator = lookup_result::iterator;
/// lookup - Find the declarations (if any) with the given Name in
/// this context. Returns a range of iterators that contains all of
@ -1780,7 +1820,7 @@ class DeclContext {
/// of looking up every possible name.
class all_lookups_iterator;
typedef llvm::iterator_range<all_lookups_iterator> lookups_range;
using lookups_range = llvm::iterator_range<all_lookups_iterator>;
lookups_range lookups() const;
lookups_range noload_lookups() const;
@ -1796,21 +1836,26 @@ class DeclContext {
all_lookups_iterator noload_lookups_end() const;
struct udir_iterator;
typedef llvm::iterator_adaptor_base<udir_iterator, lookup_iterator,
std::random_access_iterator_tag,
UsingDirectiveDecl *> udir_iterator_base;
using udir_iterator_base =
llvm::iterator_adaptor_base<udir_iterator, lookup_iterator,
std::random_access_iterator_tag,
UsingDirectiveDecl *>;
struct udir_iterator : udir_iterator_base {
udir_iterator(lookup_iterator I) : udir_iterator_base(I) {}
UsingDirectiveDecl *operator*() const;
};
typedef llvm::iterator_range<udir_iterator> udir_range;
using udir_range = llvm::iterator_range<udir_iterator>;
udir_range using_directives() const;
// These are all defined in DependentDiagnostic.h.
class ddiag_iterator;
typedef llvm::iterator_range<DeclContext::ddiag_iterator> ddiag_range;
using ddiag_range = llvm::iterator_range<DeclContext::ddiag_iterator>;
inline ddiag_range ddiags() const;
@ -1883,6 +1928,8 @@ class DeclContext {
bool Deserialize = false) const;
private:
friend class DependentDiagnostic;
void reconcileExternalVisibleStorage() const;
bool LoadLexicalDeclsFromExternalStorage() const;
@ -1894,7 +1941,6 @@ class DeclContext {
/// use of addDeclInternal().
void makeDeclVisibleInContextInternal(NamedDecl *D);
friend class DependentDiagnostic;
StoredDeclsMap *CreateStoredDeclsMap(ASTContext &C) const;
void buildLookupImpl(DeclContext *DCtx, bool Internal);
@ -1933,8 +1979,7 @@ struct cast_convert_decl_context<ToTy, true> {
}
};
} // end clang.
} // namespace clang
namespace llvm {
@ -1954,12 +1999,14 @@ struct cast_convert_val<ToTy,
return *::clang::cast_convert_decl_context<ToTy>::doit(&Val);
}
};
template<class ToTy>
struct cast_convert_val<ToTy, ::clang::DeclContext, ::clang::DeclContext> {
static ToTy &doit(::clang::DeclContext &Val) {
return *::clang::cast_convert_decl_context<ToTy>::doit(&Val);
}
};
template<class ToTy>
struct cast_convert_val<ToTy,
const ::clang::DeclContext*, const ::clang::DeclContext*> {
@ -1967,6 +2014,7 @@ struct cast_convert_val<ToTy,
return ::clang::cast_convert_decl_context<ToTy>::doit(Val);
}
};
template<class ToTy>
struct cast_convert_val<ToTy, ::clang::DeclContext*, ::clang::DeclContext*> {
static ToTy *doit(::clang::DeclContext *Val) {
@ -2003,6 +2051,6 @@ struct cast_convert_val< const ::clang::DeclContext, FromTy*, FromTy*> {
}
};
} // end namespace llvm
} // namespace llvm
#endif
#endif // LLVM_CLANG_AST_DECLBASE_H

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
//===-- DeclContextInternals.h - DeclContext Representation -----*- C++ -*-===//
//===- DeclContextInternals.h - DeclContext Representation ------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@ -11,10 +11,12 @@
// of DeclContext.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_AST_DECLCONTEXTINTERNALS_H
#define LLVM_CLANG_AST_DECLCONTEXTINTERNALS_H
#include "clang/AST/Decl.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclarationName.h"
#include "llvm/ADT/DenseMap.h"
@ -22,6 +24,7 @@
#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/SmallVector.h"
#include <algorithm>
#include <cassert>
namespace clang {
@ -30,21 +33,20 @@ class DependentDiagnostic;
/// \brief An array of decls optimized for the common case of only containing
/// one entry.
struct StoredDeclsList {
/// \brief When in vector form, this is what the Data pointer points to.
typedef SmallVector<NamedDecl *, 4> DeclsTy;
using DeclsTy = SmallVector<NamedDecl *, 4>;
/// \brief A collection of declarations, with a flag to indicate if we have
/// further external declarations.
typedef llvm::PointerIntPair<DeclsTy *, 1, bool> DeclsAndHasExternalTy;
using DeclsAndHasExternalTy = llvm::PointerIntPair<DeclsTy *, 1, bool>;
/// \brief The stored data, which will be either a pointer to a NamedDecl,
/// or a pointer to a vector with a flag to indicate if there are further
/// external declarations.
llvm::PointerUnion<NamedDecl*, DeclsAndHasExternalTy> Data;
llvm::PointerUnion<NamedDecl *, DeclsAndHasExternalTy> Data;
public:
StoredDeclsList() {}
StoredDeclsList() = default;
StoredDeclsList(StoredDeclsList &&RHS) : Data(RHS.Data) {
RHS.Data = (NamedDecl *)nullptr;
@ -186,7 +188,6 @@ struct StoredDeclsList {
/// AddSubsequentDecl - This is called on the second and later decl when it is
/// not a redeclaration to merge it into the appropriate place in our list.
///
void AddSubsequentDecl(NamedDecl *D) {
assert(!isNull() && "don't AddSubsequentDecl when we have no decls");
@ -237,28 +238,28 @@ struct StoredDeclsList {
};
class StoredDeclsMap
: public llvm::SmallDenseMap<DeclarationName, StoredDeclsList, 4> {
: public llvm::SmallDenseMap<DeclarationName, StoredDeclsList, 4> {
public:
static void DestroyAll(StoredDeclsMap *Map, bool Dependent);
private:
friend class ASTContext; // walks the chain deleting these
friend class DeclContext;
llvm::PointerIntPair<StoredDeclsMap*, 1> Previous;
};
class DependentStoredDeclsMap : public StoredDeclsMap {
public:
DependentStoredDeclsMap() : FirstDiagnostic(nullptr) {}
DependentStoredDeclsMap() = default;
private:
friend class DependentDiagnostic;
friend class DeclContext; // iterates over diagnostics
friend class DependentDiagnostic;
DependentDiagnostic *FirstDiagnostic;
DependentDiagnostic *FirstDiagnostic = nullptr;
};
} // end namespace clang
} // namespace clang
#endif
#endif // LLVM_CLANG_AST_DECLCONTEXTINTERNALS_H

View File

@ -1,4 +1,4 @@
//===-- DeclFriend.h - Classes for C++ friend declarations -*- C++ -*------===//
//===- DeclFriend.h - Classes for C++ friend declarations -------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@ -15,16 +15,30 @@
#ifndef LLVM_CLANG_AST_DECLFRIEND_H
#define LLVM_CLANG_AST_DECLFRIEND_H
#include "clang/AST/Decl.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/ExternalASTSource.h"
#include "clang/AST/TypeLoc.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/None.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/TrailingObjects.h"
#include <cassert>
#include <iterator>
namespace clang {
class ASTContext;
/// FriendDecl - Represents the declaration of a friend entity,
/// which can be a function, a type, or a templated function or type.
// For example:
/// For example:
///
/// @code
/// template <typename T> class A {
@ -41,10 +55,14 @@ class FriendDecl final
: public Decl,
private llvm::TrailingObjects<FriendDecl, TemplateParameterList *> {
virtual void anchor();
public:
typedef llvm::PointerUnion<NamedDecl*,TypeSourceInfo*> FriendUnion;
using FriendUnion = llvm::PointerUnion<NamedDecl *, TypeSourceInfo *>;
private:
friend class CXXRecordDecl;
friend class CXXRecordDecl::friend_iterator;
// The declaration that's a friend of this class.
FriendUnion Friend;
@ -64,35 +82,33 @@ class FriendDecl final
// template <class T> friend class A<T>::B;
unsigned NumTPLists : 31;
friend class CXXRecordDecl::friend_iterator;
friend class CXXRecordDecl;
FriendDecl(DeclContext *DC, SourceLocation L, FriendUnion Friend,
SourceLocation FriendL,
ArrayRef<TemplateParameterList*> FriendTypeTPLists)
: Decl(Decl::Friend, DC, L),
Friend(Friend),
NextFriend(),
FriendLoc(FriendL),
UnsupportedFriend(false),
NumTPLists(FriendTypeTPLists.size()) {
ArrayRef<TemplateParameterList *> FriendTypeTPLists)
: Decl(Decl::Friend, DC, L), Friend(Friend), FriendLoc(FriendL),
UnsupportedFriend(false), NumTPLists(FriendTypeTPLists.size()) {
for (unsigned i = 0; i < NumTPLists; ++i)
getTrailingObjects<TemplateParameterList *>()[i] = FriendTypeTPLists[i];
}
FriendDecl(EmptyShell Empty, unsigned NumFriendTypeTPLists)
: Decl(Decl::Friend, Empty), NextFriend(),
UnsupportedFriend(false),
NumTPLists(NumFriendTypeTPLists) { }
: Decl(Decl::Friend, Empty), UnsupportedFriend(false),
NumTPLists(NumFriendTypeTPLists) {}
FriendDecl *getNextFriend() {
if (!NextFriend.isOffset())
return cast_or_null<FriendDecl>(NextFriend.get(nullptr));
return getNextFriendSlowCase();
}
FriendDecl *getNextFriendSlowCase();
public:
friend class ASTDeclReader;
friend class ASTDeclWriter;
friend class ASTNodeImporter;
friend TrailingObjects;
static FriendDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation L, FriendUnion Friend_,
SourceLocation FriendL,
@ -108,9 +124,11 @@ class FriendDecl final
TypeSourceInfo *getFriendType() const {
return Friend.dyn_cast<TypeSourceInfo*>();
}
unsigned getFriendTypeNumTemplateParameterLists() const {
return NumTPLists;
}
TemplateParameterList *getFriendTypeTemplateParameterList(unsigned N) const {
assert(N < NumTPLists);
return getTrailingObjects<TemplateParameterList *>()[N];
@ -119,7 +137,7 @@ class FriendDecl final
/// If this friend declaration doesn't name a type, return the inner
/// declaration.
NamedDecl *getFriendDecl() const {
return Friend.dyn_cast<NamedDecl*>();
return Friend.dyn_cast<NamedDecl *>();
}
/// Retrieves the location of the 'friend' keyword.
@ -164,27 +182,24 @@ class FriendDecl final
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K == Decl::Friend; }
friend class ASTDeclReader;
friend class ASTDeclWriter;
friend class ASTNodeImporter;
friend TrailingObjects;
};
/// An iterator over the friend declarations of a class.
class CXXRecordDecl::friend_iterator {
friend class CXXRecordDecl;
FriendDecl *Ptr;
friend class CXXRecordDecl;
explicit friend_iterator(FriendDecl *Ptr) : Ptr(Ptr) {}
public:
friend_iterator() {}
typedef FriendDecl *value_type;
typedef FriendDecl *reference;
typedef FriendDecl *pointer;
typedef int difference_type;
typedef std::forward_iterator_tag iterator_category;
public:
friend_iterator() = default;
using value_type = FriendDecl *;
using reference = FriendDecl *;
using pointer = FriendDecl *;
using difference_type = int;
using iterator_category = std::forward_iterator_tag;
reference operator*() const { return Ptr; }
@ -240,6 +255,6 @@ inline void CXXRecordDecl::pushFriendDecl(FriendDecl *FD) {
data().FirstFriend = FD;
}
}
} // namespace clang
#endif
#endif // LLVM_CLANG_AST_DECLFRIEND_H

View File

@ -1,4 +1,4 @@
//===--- DeclGroup.h - Classes for representing groups of Decls -*- C++ -*-===//
//===- DeclGroup.h - Classes for representing groups of Decls ---*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@ -14,26 +14,26 @@
#ifndef LLVM_CLANG_AST_DECLGROUP_H
#define LLVM_CLANG_AST_DECLGROUP_H
#include "llvm/Support/DataTypes.h"
#include "llvm/Support/TrailingObjects.h"
#include <cassert>
#include <cstdint>
namespace clang {
class ASTContext;
class Decl;
class DeclGroup;
class DeclGroupIterator;
class DeclGroup final : private llvm::TrailingObjects<DeclGroup, Decl *> {
// FIXME: Include a TypeSpecifier object.
unsigned NumDecls;
unsigned NumDecls = 0;
private:
DeclGroup() : NumDecls(0) {}
DeclGroup() = default;
DeclGroup(unsigned numdecls, Decl** decls);
public:
friend TrailingObjects;
static DeclGroup *Create(ASTContext &C, Decl **Decls, unsigned NumDecls);
unsigned size() const { return NumDecls; }
@ -47,23 +47,21 @@ class DeclGroup final : private llvm::TrailingObjects<DeclGroup, Decl *> {
assert (i < NumDecls && "Out-of-bounds access.");
return getTrailingObjects<Decl *>()[i];
}
friend TrailingObjects;
};
class DeclGroupRef {
// Note this is not a PointerIntPair because we need the address of the
// non-group case to be valid as a Decl** for iteration.
enum Kind { SingleDeclKind=0x0, DeclGroupKind=0x1, Mask=0x1 };
Decl* D;
Decl* D = nullptr;
Kind getKind() const {
return (Kind) (reinterpret_cast<uintptr_t>(D) & Mask);
}
public:
DeclGroupRef() : D(nullptr) {}
DeclGroupRef() = default;
explicit DeclGroupRef(Decl* d) : D(d) {}
explicit DeclGroupRef(DeclGroup* dg)
: D((Decl*) (reinterpret_cast<uintptr_t>(dg) | DeclGroupKind)) {}
@ -76,8 +74,8 @@ class DeclGroupRef {
return DeclGroupRef(DeclGroup::Create(C, Decls, NumDecls));
}
typedef Decl** iterator;
typedef Decl* const * const_iterator;
using iterator = Decl **;
using const_iterator = Decl * const *;
bool isNull() const { return D == nullptr; }
bool isSingleDecl() const { return getKind() == SingleDeclKind; }
@ -133,22 +131,26 @@ class DeclGroupRef {
}
};
} // end clang namespace
} // namespace clang
namespace llvm {
// DeclGroupRef is "like a pointer", implement PointerLikeTypeTraits.
template <typename T>
class PointerLikeTypeTraits;
struct PointerLikeTypeTraits;
template <>
class PointerLikeTypeTraits<clang::DeclGroupRef> {
public:
struct PointerLikeTypeTraits<clang::DeclGroupRef> {
static inline void *getAsVoidPointer(clang::DeclGroupRef P) {
return P.getAsOpaquePtr();
}
static inline clang::DeclGroupRef getFromVoidPointer(void *P) {
return clang::DeclGroupRef::getFromOpaquePtr(P);
}
enum { NumLowBitsAvailable = 0 };
};
}
#endif
} // namespace llvm
#endif // LLVM_CLANG_AST_DECLGROUP_H

View File

@ -1,4 +1,4 @@
//===-- DeclLookups.h - Low-level interface to all names in a DC-*- C++ -*-===//
//===- DeclLookups.h - Low-level interface to all names in a DC -*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@ -18,6 +18,9 @@
#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclContextInternals.h"
#include "clang/AST/DeclarationName.h"
#include "clang/AST/ExternalASTSource.h"
#include <cstddef>
#include <iterator>
namespace clang {
@ -25,14 +28,15 @@ namespace clang {
/// of looking up every possible name.
class DeclContext::all_lookups_iterator {
StoredDeclsMap::iterator It, End;
public:
typedef lookup_result value_type;
typedef lookup_result reference;
typedef lookup_result pointer;
typedef std::forward_iterator_tag iterator_category;
typedef std::ptrdiff_t difference_type;
all_lookups_iterator() {}
public:
using value_type = lookup_result;
using reference = lookup_result;
using pointer = lookup_result;
using iterator_category = std::forward_iterator_tag;
using difference_type = std::ptrdiff_t;
all_lookups_iterator() = default;
all_lookups_iterator(StoredDeclsMap::iterator It,
StoredDeclsMap::iterator End)
: It(It), End(End) {}
@ -63,6 +67,7 @@ class DeclContext::all_lookups_iterator {
friend bool operator==(all_lookups_iterator x, all_lookups_iterator y) {
return x.It == y.It;
}
friend bool operator!=(all_lookups_iterator x, all_lookups_iterator y) {
return x.It != y.It;
}
@ -110,6 +115,6 @@ DeclContext::all_lookups_iterator DeclContext::noload_lookups_end() const {
return noload_lookups().end();
}
} // end namespace clang
} // namespace clang
#endif
#endif // LLVM_CLANG_AST_DECLLOOKUPS_H

File diff suppressed because it is too large Load Diff

View File

@ -100,12 +100,22 @@ class OMPThreadPrivateDecl final
///
/// Here 'omp_out += omp_in' is a combiner and 'omp_priv = 0' is an initializer.
class OMPDeclareReductionDecl final : public ValueDecl, public DeclContext {
public:
enum InitKind {
CallInit, // Initialized by function call.
DirectInit, // omp_priv(<expr>)
CopyInit // omp_priv = <expr>
};
private:
friend class ASTDeclReader;
/// \brief Combiner for declare reduction construct.
Expr *Combiner;
/// \brief Initializer for declare reduction construct.
Expr *Initializer;
/// Kind of initializer - function call or omp_priv<init_expr> initializtion.
InitKind InitializerKind = CallInit;
/// \brief Reference to the previous declare reduction construct in the same
/// scope with the same name. Required for proper templates instantiation if
/// the declare reduction construct is declared inside compound statement.
@ -117,7 +127,8 @@ class OMPDeclareReductionDecl final : public ValueDecl, public DeclContext {
DeclarationName Name, QualType Ty,
OMPDeclareReductionDecl *PrevDeclInScope)
: ValueDecl(DK, DC, L, Name, Ty), DeclContext(DK), Combiner(nullptr),
Initializer(nullptr), PrevDeclInScope(PrevDeclInScope) {}
Initializer(nullptr), InitializerKind(CallInit),
PrevDeclInScope(PrevDeclInScope) {}
void setPrevDeclInScope(OMPDeclareReductionDecl *Prev) {
PrevDeclInScope = Prev;
@ -142,8 +153,13 @@ class OMPDeclareReductionDecl final : public ValueDecl, public DeclContext {
/// construct.
Expr *getInitializer() { return Initializer; }
const Expr *getInitializer() const { return Initializer; }
/// Get initializer kind.
InitKind getInitializerKind() const { return InitializerKind; }
/// \brief Set initializer expression for the declare reduction construct.
void setInitializer(Expr *E) { Initializer = E; }
void setInitializer(Expr *E, InitKind IK) {
Initializer = E;
InitializerKind = IK;
}
/// \brief Get reference to previous declare reduction construct in the same
/// scope with the same name.

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
//===--- DeclVisitor.h - Visitor for Decl subclasses ------------*- C++ -*-===//
//===- DeclVisitor.h - Visitor for Decl subclasses --------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@ -10,27 +10,30 @@
// This file defines the DeclVisitor interface.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_AST_DECLVISITOR_H
#define LLVM_CLANG_AST_DECLVISITOR_H
#include "clang/AST/Decl.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclFriend.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclOpenMP.h"
#include "clang/AST/DeclTemplate.h"
#include "llvm/Support/ErrorHandling.h"
namespace clang {
namespace declvisitor {
template <typename T> struct make_ptr { typedef T *type; };
template <typename T> struct make_const_ptr { typedef const T *type; };
template <typename T> struct make_ptr { using type = T *; };
template <typename T> struct make_const_ptr { using type = const T *; };
/// \brief A simple visitor class that helps create declaration visitors.
template<template <typename> class Ptr, typename ImplClass, typename RetTy=void>
class Base {
public:
#define PTR(CLASS) typename Ptr<CLASS>::type
#define DISPATCH(NAME, CLASS) \
return static_cast<ImplClass*>(this)->Visit##NAME(static_cast<PTR(CLASS)>(D))
@ -57,23 +60,23 @@ class Base {
#undef DISPATCH
};
} // end namespace declvisitor
} // namespace declvisitor
/// \brief A simple visitor class that helps create declaration visitors.
///
/// This class does not preserve constness of Decl pointers (see also
/// ConstDeclVisitor).
template<typename ImplClass, typename RetTy=void>
template<typename ImplClass, typename RetTy = void>
class DeclVisitor
: public declvisitor::Base<declvisitor::make_ptr, ImplClass, RetTy> {};
/// \brief A simple visitor class that helps create declaration visitors.
///
/// This class preserves constness of Decl pointers (see also DeclVisitor).
template<typename ImplClass, typename RetTy=void>
template<typename ImplClass, typename RetTy = void>
class ConstDeclVisitor
: public declvisitor::Base<declvisitor::make_const_ptr, ImplClass, RetTy> {};
} // end namespace clang
} // namespace clang
#endif // LLVM_CLANG_AST_DECLVISITOR_H

View File

@ -1,4 +1,4 @@
//===-- DeclarationName.h - Representation of declaration names -*- C++ -*-===//
//===- DeclarationName.h - Representation of declaration names --*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@ -10,36 +10,42 @@
// This file declares the DeclarationName and DeclarationNameTable classes.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_AST_DECLARATIONNAME_H
#define LLVM_CLANG_AST_DECLARATIONNAME_H
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/DenseMapInfo.h"
#include "llvm/Support/Compiler.h"
namespace llvm {
template <typename T> struct DenseMapInfo;
}
#include "llvm/Support/type_traits.h"
#include <cassert>
#include <cstdint>
#include <cstring>
#include <string>
namespace clang {
class ASTContext;
class CXXDeductionGuideNameExtra;
class CXXLiteralOperatorIdName;
class CXXOperatorIdName;
class CXXSpecialName;
class DeclarationNameExtra;
class IdentifierInfo;
class MultiKeywordSelector;
enum OverloadedOperatorKind : int;
struct PrintingPolicy;
class QualType;
class TemplateDecl;
class Type;
class TypeSourceInfo;
class UsingDirectiveDecl;
template <typename> class CanQual;
typedef CanQual<Type> CanQualType;
class ASTContext;
template <typename> class CanQual;
class CXXDeductionGuideNameExtra;
class CXXLiteralOperatorIdName;
class CXXOperatorIdName;
class CXXSpecialName;
class DeclarationNameExtra;
class IdentifierInfo;
class MultiKeywordSelector;
enum OverloadedOperatorKind : int;
struct PrintingPolicy;
class QualType;
class TemplateDecl;
class Type;
class TypeSourceInfo;
class UsingDirectiveDecl;
using CanQualType = CanQual<Type>;
/// DeclarationName - The name of a declaration. In the common case,
/// this just stores an IdentifierInfo pointer to a normal
@ -63,9 +69,13 @@ class DeclarationName {
CXXLiteralOperatorName,
CXXUsingDirective
};
static const unsigned NumNameKinds = CXXUsingDirective + 1;
private:
friend class DeclarationNameTable;
friend class NamedDecl;
/// StoredNameKind - The kind of name that is actually stored in the
/// upper bits of the Ptr field. This is only used internally.
///
@ -99,7 +109,18 @@ class DeclarationName {
/// DeclarationNameExtra structure, whose first value will tell us
/// whether this is an Objective-C selector, C++ operator-id name,
/// or special C++ name.
uintptr_t Ptr;
uintptr_t Ptr = 0;
// Construct a declaration name from the name of a C++ constructor,
// destructor, or conversion function.
DeclarationName(DeclarationNameExtra *Name)
: Ptr(reinterpret_cast<uintptr_t>(Name)) {
assert((Ptr & PtrMask) == 0 && "Improperly aligned DeclarationNameExtra");
Ptr |= StoredDeclarationNameExtra;
}
/// Construct a declaration name from a raw pointer.
DeclarationName(uintptr_t Ptr) : Ptr(Ptr) {}
/// getStoredNameKind - Return the kind of object that is stored in
/// Ptr.
@ -146,36 +167,22 @@ class DeclarationName {
return nullptr;
}
// Construct a declaration name from the name of a C++ constructor,
// destructor, or conversion function.
DeclarationName(DeclarationNameExtra *Name)
: Ptr(reinterpret_cast<uintptr_t>(Name)) {
assert((Ptr & PtrMask) == 0 && "Improperly aligned DeclarationNameExtra");
Ptr |= StoredDeclarationNameExtra;
}
/// Construct a declaration name from a raw pointer.
DeclarationName(uintptr_t Ptr) : Ptr(Ptr) { }
friend class DeclarationNameTable;
friend class NamedDecl;
/// 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.
DeclarationName() : Ptr(0) { }
DeclarationName() = default;
// Construct a declaration name from an IdentifierInfo *.
DeclarationName(const IdentifierInfo *II)
: Ptr(reinterpret_cast<uintptr_t>(II)) {
: Ptr(reinterpret_cast<uintptr_t>(II)) {
assert((Ptr & PtrMask) == 0 && "Improperly aligned IdentifierInfo");
}
// Construct a declaration name from an Objective-C selector.
DeclarationName(Selector Sel) : Ptr(Sel.InfoPtr) { }
DeclarationName(Selector Sel) : Ptr(Sel.InfoPtr) {}
/// getUsingDirectiveName - Return name for all using-directives.
static DeclarationName getUsingDirectiveName();
@ -344,16 +351,24 @@ inline bool operator>=(DeclarationName LHS, DeclarationName RHS) {
/// getCXXConstructorName).
class DeclarationNameTable {
const ASTContext &Ctx;
void *CXXSpecialNamesImpl; // Actually a FoldingSet<CXXSpecialName> *
CXXOperatorIdName *CXXOperatorNames; // Operator names
void *CXXLiteralOperatorNames; // Actually a CXXOperatorIdName*
void *CXXDeductionGuideNames; // FoldingSet<CXXDeductionGuideNameExtra> *
DeclarationNameTable(const DeclarationNameTable&) = delete;
void operator=(const DeclarationNameTable&) = delete;
// Actually a FoldingSet<CXXSpecialName> *
void *CXXSpecialNamesImpl;
// Operator names
CXXOperatorIdName *CXXOperatorNames;
// Actually a CXXOperatorIdName*
void *CXXLiteralOperatorNames;
// FoldingSet<CXXDeductionGuideNameExtra> *
void *CXXDeductionGuideNames;
public:
DeclarationNameTable(const ASTContext &C);
DeclarationNameTable(const DeclarationNameTable &) = delete;
DeclarationNameTable &operator=(const DeclarationNameTable &) = delete;
~DeclarationNameTable();
/// getIdentifier - Create a declaration name that is a simple
@ -428,10 +443,10 @@ struct DeclarationNameLoc {
};
DeclarationNameLoc(DeclarationName Name);
// FIXME: this should go away once all DNLocs are properly initialized.
DeclarationNameLoc() { memset((void*) this, 0, sizeof(*this)); }
}; // struct DeclarationNameLoc
};
/// DeclarationNameInfo - A collector data type for bundling together
/// a DeclarationName and the correspnding source/type location info.
@ -439,29 +454,33 @@ struct DeclarationNameInfo {
private:
/// Name - The declaration name, also encoding name kind.
DeclarationName Name;
/// Loc - The main source location for the declaration name.
SourceLocation NameLoc;
/// Info - Further source/type location info for special kinds of names.
DeclarationNameLoc LocInfo;
public:
// FIXME: remove it.
DeclarationNameInfo() {}
DeclarationNameInfo() = default;
DeclarationNameInfo(DeclarationName Name, SourceLocation NameLoc)
: Name(Name), NameLoc(NameLoc), LocInfo(Name) {}
: Name(Name), NameLoc(NameLoc), LocInfo(Name) {}
DeclarationNameInfo(DeclarationName Name, SourceLocation NameLoc,
DeclarationNameLoc LocInfo)
: Name(Name), NameLoc(NameLoc), LocInfo(LocInfo) {}
: Name(Name), NameLoc(NameLoc), LocInfo(LocInfo) {}
/// getName - Returns the embedded declaration name.
DeclarationName getName() const { return Name; }
/// setName - Sets the embedded declaration name.
void setName(DeclarationName N) { Name = N; }
/// getLoc - Returns the main location of the declaration name.
SourceLocation getLoc() const { return NameLoc; }
/// setLoc - Sets the main location of the declaration name.
void setLoc(SourceLocation L) { NameLoc = L; }
@ -477,6 +496,7 @@ struct DeclarationNameInfo {
Name.getNameKind() == DeclarationName::CXXConversionFunctionName);
return LocInfo.NamedType.TInfo;
}
/// setNamedTypeInfo - Sets the source type info associated to
/// the name. Assumes it is a constructor, destructor or conversion.
void setNamedTypeInfo(TypeSourceInfo *TInfo) {
@ -495,6 +515,7 @@ struct DeclarationNameInfo {
SourceLocation::getFromRawEncoding(LocInfo.CXXOperatorName.EndOpNameLoc)
);
}
/// setCXXOperatorNameRange - Sets the range of the operator name
/// (without the operator keyword). Assumes it is a C++ operator.
void setCXXOperatorNameRange(SourceRange R) {
@ -511,6 +532,7 @@ struct DeclarationNameInfo {
return SourceLocation::
getFromRawEncoding(LocInfo.CXXLiteralOperatorName.OpNameLoc);
}
/// setCXXLiteralOperatorNameLoc - Sets the location of the literal
/// operator name (not the operator keyword).
/// Assumes it is a literal operator.
@ -534,15 +556,19 @@ struct DeclarationNameInfo {
/// getBeginLoc - Retrieve the location of the first token.
SourceLocation getBeginLoc() const { return NameLoc; }
/// getEndLoc - Retrieve the location of the last token.
SourceLocation getEndLoc() const;
/// getSourceRange - The range of the declaration name.
SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(getLocStart(), getLocEnd());
}
SourceLocation getLocStart() const LLVM_READONLY {
return getBeginLoc();
}
SourceLocation getLocEnd() const LLVM_READONLY {
SourceLocation EndLoc = getEndLoc();
return EndLoc.isValid() ? EndLoc : getLocStart();
@ -573,9 +599,10 @@ inline raw_ostream &operator<<(raw_ostream &OS,
return OS;
}
} // end namespace clang
} // namespace clang
namespace llvm {
/// Define DenseMapInfo so that DeclarationNames can be used as keys
/// in DenseMap and DenseSets.
template<>
@ -601,6 +628,6 @@ struct DenseMapInfo<clang::DeclarationName> {
template <>
struct isPodLike<clang::DeclarationName> { static const bool value = true; };
} // end namespace llvm
} // namespace llvm
#endif
#endif // LLVM_CLANG_AST_DECLARATIONNAME_H

View File

@ -1,4 +1,4 @@
//===-- DependentDiagnostic.h - Dependently-generated diagnostics -*- C++ -*-=//
//==- DependentDiagnostic.h - Dependently-generated diagnostics --*- C++ -*-==//
//
// The LLVM Compiler Infrastructure
//
@ -23,6 +23,9 @@
#include "clang/AST/Type.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/Specifiers.h"
#include <cassert>
#include <iterator>
namespace clang {
@ -94,6 +97,9 @@ class DependentDiagnostic {
}
private:
friend class DeclContext::ddiag_iterator;
friend class DependentStoredDeclsMap;
DependentDiagnostic(const PartialDiagnostic &PDiag,
PartialDiagnostic::Storage *Storage)
: Diag(PDiag, Storage) {}
@ -102,8 +108,6 @@ class DependentDiagnostic {
DeclContext *Parent,
const PartialDiagnostic &PDiag);
friend class DependentStoredDeclsMap;
friend class DeclContext::ddiag_iterator;
DependentDiagnostic *NextDiagnostic;
PartialDiagnostic Diag;
@ -118,19 +122,17 @@ class DependentDiagnostic {
} AccessData;
};
///
/// An iterator over the dependent diagnostics in a dependent context.
class DeclContext::ddiag_iterator {
public:
ddiag_iterator() : Ptr(nullptr) {}
ddiag_iterator() = default;
explicit ddiag_iterator(DependentDiagnostic *Ptr) : Ptr(Ptr) {}
typedef DependentDiagnostic *value_type;
typedef DependentDiagnostic *reference;
typedef DependentDiagnostic *pointer;
typedef int difference_type;
typedef std::forward_iterator_tag iterator_category;
using value_type = DependentDiagnostic *;
using reference = DependentDiagnostic *;
using pointer = DependentDiagnostic *;
using difference_type = int;
using iterator_category = std::forward_iterator_tag;
reference operator*() const { return Ptr; }
@ -168,7 +170,7 @@ class DeclContext::ddiag_iterator {
}
private:
DependentDiagnostic *Ptr;
DependentDiagnostic *Ptr = nullptr;
};
inline DeclContext::ddiag_range DeclContext::ddiags() const {
@ -184,6 +186,6 @@ inline DeclContext::ddiag_range DeclContext::ddiags() const {
return ddiag_range(ddiag_iterator(Map->FirstDiagnostic), ddiag_iterator());
}
}
} // namespace clang
#endif
#endif // LLVM_CLANG_AST_DEPENDENTDIAGNOSTIC_H

View File

@ -24,6 +24,7 @@
#include "clang/AST/Type.h"
#include "clang/Basic/CharInfo.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/SyncScope.h"
#include "clang/Basic/TypeTraits.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/APSInt.h"
@ -274,6 +275,7 @@ class Expr : public Stmt {
MLV_LValueCast, // Specialized form of MLV_InvalidExpression.
MLV_IncompleteType,
MLV_ConstQualified,
MLV_ConstQualifiedField,
MLV_ConstAddrSpace,
MLV_ArrayType,
MLV_NoSetterProperty,
@ -323,6 +325,7 @@ class Expr : public Stmt {
CM_LValueCast, // Same as CM_RValue, but indicates GCC cast-as-lvalue ext
CM_NoSetterProperty,// Implicit assignment to ObjC property without setter
CM_ConstQualified,
CM_ConstQualifiedField,
CM_ConstAddrSpace,
CM_ArrayType,
CM_IncompleteType
@ -2345,6 +2348,12 @@ class CallExpr : public Expr {
SourceLocation getLocStart() const LLVM_READONLY;
SourceLocation getLocEnd() const LLVM_READONLY;
bool isCallToStdMove() const {
const FunctionDecl* FD = getDirectCallee();
return getNumArgs() == 1 && FD && FD->isInStdNamespace() &&
FD->getIdentifier() && FD->getIdentifier()->isStr("move");
}
static bool classof(const Stmt *T) {
return T->getStmtClass() >= firstCallExprConstant &&
T->getStmtClass() <= lastCallExprConstant;
@ -2733,7 +2742,6 @@ class CastExpr : public Expr {
ty->containsUnexpandedParameterPack()) ||
(op && op->containsUnexpandedParameterPack()))),
Op(op) {
assert(kind != CK_Invalid && "creating cast with invalid cast kind");
CastExprBits.Kind = kind;
setBasePathSize(BasePathSize);
assert(CastConsistency());
@ -2771,6 +2779,16 @@ class CastExpr : public Expr {
path_const_iterator path_begin() const { return path_buffer(); }
path_const_iterator path_end() const { return path_buffer() + path_size(); }
const FieldDecl *getTargetUnionField() const {
assert(getCastKind() == CK_ToUnion);
return getTargetFieldForToUnionCast(getType(), getSubExpr()->getType());
}
static const FieldDecl *getTargetFieldForToUnionCast(QualType unionType,
QualType opType);
static const FieldDecl *getTargetFieldForToUnionCast(const RecordDecl *RD,
QualType opType);
static bool classof(const Stmt *T) {
return T->getStmtClass() >= firstCastExprConstant &&
T->getStmtClass() <= lastCastExprConstant;
@ -3054,7 +3072,7 @@ class BinaryOperator : public Expr {
static bool isEqualityOp(Opcode Opc) { return Opc == BO_EQ || Opc == BO_NE; }
bool isEqualityOp() const { return isEqualityOp(getOpcode()); }
static bool isComparisonOp(Opcode Opc) { return Opc >= BO_LT && Opc<=BO_NE; }
static bool isComparisonOp(Opcode Opc) { return Opc >= BO_Cmp && Opc<=BO_NE; }
bool isComparisonOp() const { return isComparisonOp(getOpcode()); }
static Opcode negateComparisonOp(Opcode Opc) {
@ -3113,6 +3131,12 @@ class BinaryOperator : public Expr {
return isShiftAssignOp(getOpcode());
}
// Return true if a binary operator using the specified opcode and operands
// would match the 'p = (i8*)nullptr + n' idiom for casting a pointer-sized
// integer to a pointer.
static bool isNullPointerArithmeticExtension(ASTContext &Ctx, Opcode Opc,
Expr *LHS, Expr *RHS);
static bool classof(const Stmt *S) {
return S->getStmtClass() >= firstBinaryOperatorConstant &&
S->getStmtClass() <= lastBinaryOperatorConstant;
@ -3986,6 +4010,10 @@ class InitListExpr : public Expr {
/// initializer)?
bool isTransparent() const;
/// Is this the zero initializer {0} in a language which considers it
/// idiomatic?
bool isIdiomaticZeroInitializer(const LangOptions &LangOpts) const;
SourceLocation getLBraceLoc() const { return LBraceLoc; }
void setLBraceLoc(SourceLocation Loc) { LBraceLoc = Loc; }
SourceLocation getRBraceLoc() const { return RBraceLoc; }
@ -3995,6 +4023,9 @@ class InitListExpr : public Expr {
InitListExpr *getSemanticForm() const {
return isSemanticForm() ? nullptr : AltForm.getPointer();
}
bool isSyntacticForm() const {
return !AltForm.getInt() || !AltForm.getPointer();
}
InitListExpr *getSyntacticForm() const {
return isSemanticForm() ? AltForm.getPointer() : nullptr;
}
@ -5064,9 +5095,11 @@ class PseudoObjectExpr final
/// AtomicExpr - Variadic atomic builtins: __atomic_exchange, __atomic_fetch_*,
/// __atomic_load, __atomic_store, and __atomic_compare_exchange_*, for the
/// similarly-named C++11 instructions, and __c11 variants for <stdatomic.h>.
/// All of these instructions take one primary pointer and at least one memory
/// order.
/// similarly-named C++11 instructions, and __c11 variants for <stdatomic.h>,
/// and corresponding __opencl_atomic_* for OpenCL 2.0.
/// All of these instructions take one primary pointer, at least one memory
/// order. The instructions for which getScopeModel returns non-null value
/// take one synch scope.
class AtomicExpr : public Expr {
public:
enum AtomicOp {
@ -5078,14 +5111,16 @@ class AtomicExpr : public Expr {
};
private:
/// \brief Location of sub-expressions.
/// The location of Scope sub-expression is NumSubExprs - 1, which is
/// not fixed, therefore is not defined in enum.
enum { PTR, ORDER, VAL1, ORDER_FAIL, VAL2, WEAK, END_EXPR };
Stmt* SubExprs[END_EXPR];
Stmt *SubExprs[END_EXPR + 1];
unsigned NumSubExprs;
SourceLocation BuiltinLoc, RParenLoc;
AtomicOp Op;
friend class ASTStmtReader;
public:
AtomicExpr(SourceLocation BLoc, ArrayRef<Expr*> args, QualType t,
AtomicOp op, SourceLocation RP);
@ -5103,8 +5138,12 @@ class AtomicExpr : public Expr {
Expr *getOrder() const {
return cast<Expr>(SubExprs[ORDER]);
}
Expr *getScope() const {
assert(getScopeModel() && "No scope");
return cast<Expr>(SubExprs[NumSubExprs - 1]);
}
Expr *getVal1() const {
if (Op == AO__c11_atomic_init)
if (Op == AO__c11_atomic_init || Op == AO__opencl_atomic_init)
return cast<Expr>(SubExprs[ORDER]);
assert(NumSubExprs > VAL1);
return cast<Expr>(SubExprs[VAL1]);
@ -5123,6 +5162,7 @@ class AtomicExpr : public Expr {
assert(NumSubExprs > WEAK);
return cast<Expr>(SubExprs[WEAK]);
}
QualType getValueType() const;
AtomicOp getOp() const { return Op; }
unsigned getNumSubExprs() const { return NumSubExprs; }
@ -5139,10 +5179,17 @@ class AtomicExpr : public Expr {
bool isCmpXChg() const {
return getOp() == AO__c11_atomic_compare_exchange_strong ||
getOp() == AO__c11_atomic_compare_exchange_weak ||
getOp() == AO__opencl_atomic_compare_exchange_strong ||
getOp() == AO__opencl_atomic_compare_exchange_weak ||
getOp() == AO__atomic_compare_exchange ||
getOp() == AO__atomic_compare_exchange_n;
}
bool isOpenCL() const {
return getOp() >= AO__opencl_atomic_init &&
getOp() <= AO__opencl_atomic_fetch_max;
}
SourceLocation getBuiltinLoc() const { return BuiltinLoc; }
SourceLocation getRParenLoc() const { return RParenLoc; }
@ -5160,6 +5207,24 @@ class AtomicExpr : public Expr {
const_child_range children() const {
return const_child_range(SubExprs, SubExprs + NumSubExprs);
}
/// \brief Get atomic scope model for the atomic op code.
/// \return empty atomic scope model if the atomic op code does not have
/// scope operand.
static std::unique_ptr<AtomicScopeModel> getScopeModel(AtomicOp Op) {
auto Kind =
(Op >= AO__opencl_atomic_load && Op <= AO__opencl_atomic_fetch_max)
? AtomicScopeModelKind::OpenCL
: AtomicScopeModelKind::None;
return AtomicScopeModel::create(Kind);
}
/// \brief Get atomic scope model.
/// \return empty atomic scope model if this atomic expression does not have
/// scope operand.
std::unique_ptr<AtomicScopeModel> getScopeModel() const {
return getScopeModel(getOp());
}
};
/// TypoExpr - Internal placeholder for expressions where typo correction

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -16,34 +16,159 @@
#include "clang/AST/ASTImporter.h"
#include "clang/AST/ExternalASTSource.h"
#include "llvm/Support/raw_ostream.h"
namespace clang {
/// ExternalASTSource implementation that merges information from several
/// ASTContexts.
///
/// ExtermalASTMerger maintains a vector of ASTImporters that it uses to import
/// (potentially incomplete) Decls and DeclContexts from the source ASTContexts
/// in response to ExternalASTSource API calls.
///
/// When lookup occurs in the resulting imported DeclContexts, the original
/// DeclContexts need to be queried. Roughly, there are three cases here:
///
/// - The DeclContext of origin can be found by simple name lookup. In this
/// case, no additional state is required.
///
/// - The DeclContext of origin is different from what would be found by name
/// lookup. In this case, Origins contains an entry overriding lookup and
/// specifying the correct pair of DeclContext/ASTContext.
///
/// - The DeclContext of origin was determined by another ExterenalASTMerger.
/// (This is possible when the source ASTContext for one of the Importers has
/// its own ExternalASTMerger). The origin must be properly forwarded in this
/// case.
///
/// ExternalASTMerger's job is to maintain the data structures necessary to
/// allow this. The data structures themselves can be extracted (read-only) and
/// copied for re-use.
class ExternalASTMerger : public ExternalASTSource {
public:
struct ImporterPair {
std::unique_ptr<ASTImporter> Forward;
std::unique_ptr<ASTImporter> Reverse;
/// A single origin for a DeclContext. Unlike Decls, DeclContexts do
/// not allow their containing ASTContext to be determined in all cases.
struct DCOrigin {
DeclContext *DC;
ASTContext *AST;
};
typedef std::map<const DeclContext *, DCOrigin> OriginMap;
typedef std::vector<std::unique_ptr<ASTImporter>> ImporterVector;
private:
std::vector<ImporterPair> Importers;
/// One importer exists for each source.
ImporterVector Importers;
/// Overrides in case name lookup would return nothing or would return
/// the wrong thing.
OriginMap Origins;
/// The installed log stream.
llvm::raw_ostream *LogStream;
public:
struct ImporterEndpoint {
/// The target for an ExternalASTMerger.
///
/// ASTImporters require both ASTContext and FileManager to be able to
/// import SourceLocations properly.
struct ImporterTarget {
ASTContext &AST;
FileManager &FM;
};
ExternalASTMerger(const ImporterEndpoint &Target,
llvm::ArrayRef<ImporterEndpoint> Sources);
/// A source for an ExternalASTMerger.
///
/// ASTImporters require both ASTContext and FileManager to be able to
/// import SourceLocations properly. Additionally, when import occurs for
/// a DeclContext whose origin has been overridden, then this
/// ExternalASTMerger must be able to determine that.
struct ImporterSource {
ASTContext &AST;
FileManager &FM;
const OriginMap &OM;
};
private:
/// The target for this ExtenralASTMerger.
ImporterTarget Target;
public:
ExternalASTMerger(const ImporterTarget &Target,
llvm::ArrayRef<ImporterSource> Sources);
/// Add a set of ASTContexts as possible origins.
///
/// Usually the set will be initialized in the constructor, but long-lived
/// ExternalASTMergers may neeed to import from new sources (for example,
/// newly-parsed source files).
///
/// Ensures that Importers does not gain duplicate entries as a result.
void AddSources(llvm::ArrayRef<ImporterSource> Sources);
/// Remove a set of ASTContexts as possible origins.
///
/// Sometimes an origin goes away (for example, if a source file gets
/// superseded by a newer version).
///
/// The caller is responsible for ensuring that this doesn't leave
/// DeclContexts that can't be completed.
void RemoveSources(llvm::ArrayRef<ImporterSource> Sources);
/// Implementation of the ExternalASTSource API.
bool FindExternalVisibleDeclsByName(const DeclContext *DC,
DeclarationName Name) override;
/// Implementation of the ExternalASTSource API.
void
FindExternalLexicalDecls(const DeclContext *DC,
llvm::function_ref<bool(Decl::Kind)> IsKindWeWant,
SmallVectorImpl<Decl *> &Result) override;
/// Implementation of the ExternalASTSource API.
void CompleteType(TagDecl *Tag) override;
/// Implementation of the ExternalASTSource API.
void CompleteType(ObjCInterfaceDecl *Interface) override;
/// Returns true if DC can be found in any source AST context.
bool CanComplete(DeclContext *DC);
/// Records an origin in Origins only if name lookup would find
/// something different or nothing at all.
void MaybeRecordOrigin(const DeclContext *ToDC, DCOrigin Origin);
/// Regardless of any checks, override the Origin for a DeclContext.
void ForceRecordOrigin(const DeclContext *ToDC, DCOrigin Origin);
/// Get a read-only view of the Origins map, for use in constructing
/// an ImporterSource for another ExternalASTMerger.
const OriginMap &GetOrigins() { return Origins; }
/// Returns true if Importers contains an ASTImporter whose source is
/// OriginContext.
bool HasImporterForOrigin(ASTContext &OriginContext);
/// Returns a reference to the ASTRImporter from Importers whose origin
/// is OriginContext. This allows manual import of ASTs while preserving the
/// OriginMap correctly.
ASTImporter &ImporterForOrigin(ASTContext &OriginContext);
/// Sets the current log stream.
void SetLogStream(llvm::raw_string_ostream &Stream) { LogStream = &Stream; }
private:
/// Records and origin in Origins.
void RecordOriginImpl(const DeclContext *ToDC, DCOrigin Origin,
ASTImporter &importer);
/// Performs an action for every DeclContext that is identified as
/// corresponding (either by forced origin or by name lookup) to DC.
template <typename CallbackType>
void ForEachMatchingDC(const DeclContext *DC, CallbackType Callback);
public:
/// Log something if there is a logging callback installed.
llvm::raw_ostream &logs() { return *LogStream; }
/// True if the log stream is not llvm::nulls();
bool LoggingEnabled() { return LogStream != &llvm::nulls(); }
};
} // end namespace clang

View File

@ -1,4 +1,4 @@
//===--- ExternalASTSource.h - Abstract External AST Interface --*- C++ -*-===//
//===- ExternalASTSource.h - Abstract External AST Interface ----*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@ -11,24 +11,44 @@
// construction of AST nodes from some external source.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_AST_EXTERNALASTSOURCE_H
#define LLVM_CLANG_AST_EXTERNALASTSOURCE_H
#include "clang/AST/CharUnits.h"
#include "clang/AST/DeclBase.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/Module.h"
#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/iterator.h"
#include "llvm/Support/PointerLikeTypeTraits.h"
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <iterator>
#include <string>
#include <utility>
namespace clang {
class ASTConsumer;
class ASTContext;
class CXXBaseSpecifier;
class CXXCtorInitializer;
class CXXRecordDecl;
class DeclarationName;
class ExternalSemaSource; // layering violation required for downcasting
class FieldDecl;
class Module;
class IdentifierInfo;
class NamedDecl;
class ObjCInterfaceDecl;
class RecordDecl;
class Selector;
class Stmt;
@ -42,30 +62,31 @@ class TagDecl;
/// actual type and declaration nodes, and read parts of declaration
/// contexts.
class ExternalASTSource : public RefCountedBase<ExternalASTSource> {
friend class ExternalSemaSource;
/// Generation number for this external AST source. Must be increased
/// whenever we might have added new redeclarations for existing decls.
uint32_t CurrentGeneration;
uint32_t CurrentGeneration = 0;
/// \brief Whether this AST source also provides information for
/// semantic analysis.
bool SemaSource;
friend class ExternalSemaSource;
bool SemaSource = false;
public:
ExternalASTSource() : CurrentGeneration(0), SemaSource(false) { }
ExternalASTSource() = default;
virtual ~ExternalASTSource();
/// \brief RAII class for safely pairing a StartedDeserializing call
/// with FinishedDeserializing.
class Deserializing {
ExternalASTSource *Source;
public:
explicit Deserializing(ExternalASTSource *source) : Source(source) {
assert(Source);
Source->StartedDeserializing();
}
~Deserializing() {
Source->FinishedDeserializing();
}
@ -122,7 +143,7 @@ class ExternalASTSource : public RefCountedBase<ExternalASTSource> {
virtual CXXBaseSpecifier *GetExternalCXXBaseSpecifiers(uint64_t Offset);
/// \brief Update an out-of-date identifier.
virtual void updateOutOfDateIdentifier(IdentifierInfo &II) { }
virtual void updateOutOfDateIdentifier(IdentifierInfo &II) {}
/// \brief Find all declarations with the given name in the given context,
/// and add them to the context by calling SetExternalVisibleDeclsForName
@ -154,12 +175,13 @@ class ExternalASTSource : public RefCountedBase<ExternalASTSource> {
const Module *ClangModule = nullptr;
public:
ASTSourceDescriptor(){};
ASTSourceDescriptor() = default;
ASTSourceDescriptor(StringRef Name, StringRef Path, StringRef ASTFile,
ASTFileSignature Signature)
: PCHModuleName(std::move(Name)), Path(std::move(Path)),
ASTFile(std::move(ASTFile)), Signature(Signature){};
ASTFile(std::move(ASTFile)), Signature(Signature) {}
ASTSourceDescriptor(const Module &M);
std::string getModuleName() const;
StringRef getPath() const { return Path; }
StringRef getASTFile() const { return ASTFile; }
@ -246,7 +268,6 @@ class ExternalASTSource : public RefCountedBase<ExternalASTSource> {
/// The default implementation of this method is a no-op.
virtual void PrintStats();
/// \brief Perform layout on the given record.
///
/// This routine allows the external AST source to provide an specific
@ -289,7 +310,7 @@ class ExternalASTSource : public RefCountedBase<ExternalASTSource> {
size_t mmap_bytes;
MemoryBufferSizes(size_t malloc_bytes, size_t mmap_bytes)
: malloc_bytes(malloc_bytes), mmap_bytes(mmap_bytes) {}
: malloc_bytes(malloc_bytes), mmap_bytes(mmap_bytes) {}
};
/// Return the amount of memory used by memory buffers, breaking down
@ -329,12 +350,12 @@ struct LazyOffsetPtr {
///
/// If the low bit is clear, a pointer to the AST node. If the low
/// bit is set, the upper 63 bits are the offset.
mutable uint64_t Ptr;
mutable uint64_t Ptr = 0;
public:
LazyOffsetPtr() : Ptr(0) { }
LazyOffsetPtr() = default;
explicit LazyOffsetPtr(T *Ptr) : Ptr(reinterpret_cast<uint64_t>(Ptr)) {}
explicit LazyOffsetPtr(T *Ptr) : Ptr(reinterpret_cast<uint64_t>(Ptr)) { }
explicit LazyOffsetPtr(uint64_t Offset) : Ptr((Offset << 1) | 0x01) {
assert((Offset << 1 >> 1) == Offset && "Offsets must require < 63 bits");
if (Offset == 0)
@ -392,15 +413,16 @@ struct LazyGenerationalUpdatePtr {
/// A cache of the value of this pointer, in the most recent generation in
/// which we queried it.
struct LazyData {
LazyData(ExternalASTSource *Source, T Value)
: ExternalSource(Source), LastGeneration(0), LastValue(Value) {}
ExternalASTSource *ExternalSource;
uint32_t LastGeneration;
uint32_t LastGeneration = 0;
T LastValue;
LazyData(ExternalASTSource *Source, T Value)
: ExternalSource(Source), LastValue(Value) {}
};
// Our value is represented as simply T if there is no external AST source.
typedef llvm::PointerUnion<T, LazyData*> ValueType;
using ValueType = llvm::PointerUnion<T, LazyData*>;
ValueType Value;
LazyGenerationalUpdatePtr(ValueType V) : Value(V) {}
@ -459,25 +481,31 @@ struct LazyGenerationalUpdatePtr {
return LazyGenerationalUpdatePtr(ValueType::getFromOpaqueValue(Ptr));
}
};
} // end namespace clang
} // namespace clang
/// Specialize PointerLikeTypeTraits to allow LazyGenerationalUpdatePtr to be
/// placed into a PointerUnion.
namespace llvm {
template<typename Owner, typename T,
void (clang::ExternalASTSource::*Update)(Owner)>
struct PointerLikeTypeTraits<
clang::LazyGenerationalUpdatePtr<Owner, T, Update>> {
typedef clang::LazyGenerationalUpdatePtr<Owner, T, Update> Ptr;
using Ptr = clang::LazyGenerationalUpdatePtr<Owner, T, Update>;
static void *getAsVoidPointer(Ptr P) { return P.getOpaqueValue(); }
static Ptr getFromVoidPointer(void *P) { return Ptr::getFromOpaqueValue(P); }
enum {
NumLowBitsAvailable = PointerLikeTypeTraits<T>::NumLowBitsAvailable - 1
};
};
}
} // namespace llvm
namespace clang {
/// \brief Represents a lazily-loaded vector of data.
///
/// The lazily-loaded vector of data contains data that is partially loaded
@ -511,13 +539,14 @@ class LazyVector {
class iterator
: public llvm::iterator_adaptor_base<
iterator, int, std::random_access_iterator_tag, T, int, T *, T &> {
friend class LazyVector;
LazyVector *Self;
iterator(LazyVector *Self, int Position)
: iterator::iterator_adaptor_base(Position), Self(Self) {}
bool isLoaded() const { return this->I < 0; }
friend class LazyVector;
public:
iterator() : iterator(nullptr, 0) {}
@ -562,23 +591,23 @@ class LazyVector {
};
/// \brief A lazy pointer to a statement.
typedef LazyOffsetPtr<Stmt, uint64_t, &ExternalASTSource::GetExternalDeclStmt>
LazyDeclStmtPtr;
using LazyDeclStmtPtr =
LazyOffsetPtr<Stmt, uint64_t, &ExternalASTSource::GetExternalDeclStmt>;
/// \brief A lazy pointer to a declaration.
typedef LazyOffsetPtr<Decl, uint32_t, &ExternalASTSource::GetExternalDecl>
LazyDeclPtr;
using LazyDeclPtr =
LazyOffsetPtr<Decl, uint32_t, &ExternalASTSource::GetExternalDecl>;
/// \brief A lazy pointer to a set of CXXCtorInitializers.
typedef LazyOffsetPtr<CXXCtorInitializer *, uint64_t,
&ExternalASTSource::GetExternalCXXCtorInitializers>
LazyCXXCtorInitializersPtr;
using LazyCXXCtorInitializersPtr =
LazyOffsetPtr<CXXCtorInitializer *, uint64_t,
&ExternalASTSource::GetExternalCXXCtorInitializers>;
/// \brief A lazy pointer to a set of CXXBaseSpecifiers.
typedef LazyOffsetPtr<CXXBaseSpecifier, uint64_t,
&ExternalASTSource::GetExternalCXXBaseSpecifiers>
LazyCXXBaseSpecifiersPtr;
using LazyCXXBaseSpecifiersPtr =
LazyOffsetPtr<CXXBaseSpecifier, uint64_t,
&ExternalASTSource::GetExternalCXXBaseSpecifiers>;
} // end namespace clang
} // namespace clang
#endif
#endif // LLVM_CLANG_AST_EXTERNALASTSOURCE_H

View File

@ -1,4 +1,4 @@
//===--- GlobalDecl.h - Global declaration holder ---------------*- C++ -*-===//
//===- GlobalDecl.h - Global declaration holder -----------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@ -19,6 +19,12 @@
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclOpenMP.h"
#include "clang/Basic/ABI.h"
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/DenseMapInfo.h"
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/type_traits.h"
#include <cassert>
namespace clang {
@ -27,7 +33,7 @@ namespace clang {
/// a CXXDestructorDecl and the destructor type (Base, Complete) or
/// a VarDecl, a FunctionDecl or a BlockDecl.
class GlobalDecl {
llvm::PointerIntPair<const Decl*, 2> Value;
llvm::PointerIntPair<const Decl *, 2> Value;
void Init(const Decl *D) {
assert(!isa<CXXConstructorDecl>(D) && "Use other ctor with ctor decls!");
@ -37,19 +43,15 @@ class GlobalDecl {
}
public:
GlobalDecl() {}
GlobalDecl() = default;
GlobalDecl(const VarDecl *D) { Init(D);}
GlobalDecl(const FunctionDecl *D) { Init(D); }
GlobalDecl(const BlockDecl *D) { Init(D); }
GlobalDecl(const CapturedDecl *D) { Init(D); }
GlobalDecl(const ObjCMethodDecl *D) { Init(D); }
GlobalDecl(const OMPDeclareReductionDecl *D) { Init(D); }
GlobalDecl(const CXXConstructorDecl *D, CXXCtorType Type)
: Value(D, Type) {}
GlobalDecl(const CXXDestructorDecl *D, CXXDtorType Type)
: Value(D, Type) {}
GlobalDecl(const CXXConstructorDecl *D, CXXCtorType Type) : Value(D, Type) {}
GlobalDecl(const CXXDestructorDecl *D, CXXDtorType Type) : Value(D, Type) {}
GlobalDecl getCanonicalDecl() const {
GlobalDecl CanonGD;
@ -90,10 +92,9 @@ class GlobalDecl {
}
};
} // end namespace clang
} // namespace clang
namespace llvm {
template<class> struct DenseMapInfo;
template<> struct DenseMapInfo<clang::GlobalDecl> {
static inline clang::GlobalDecl getEmptyKey() {
@ -113,7 +114,6 @@ namespace llvm {
clang::GlobalDecl RHS) {
return LHS == RHS;
}
};
// GlobalDecl isn't *technically* a POD type. However, its copy constructor,
@ -122,6 +122,7 @@ namespace llvm {
struct isPodLike<clang::GlobalDecl> {
static const bool value = true;
};
} // end namespace llvm
#endif
} // namespace llvm
#endif // LLVM_CLANG_AST_GLOBALDECL_H

View File

@ -0,0 +1,164 @@
//===--- LexicallyOrderedRecursiveASTVisitor.h - ----------------*- 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 LexicallyOrderedRecursiveASTVisitor interface, which
// recursively traverses the entire AST in a lexical order.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_AST_LEXICALLY_ORDERED_RECURSIVEASTVISITOR_H
#define LLVM_CLANG_AST_LEXICALLY_ORDERED_RECURSIVEASTVISITOR_H
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/Support/SaveAndRestore.h"
namespace clang {
/// A RecursiveASTVisitor subclass that guarantees that AST traversal is
/// performed in a lexical order (i.e. the order in which declarations are
/// written in the source).
///
/// RecursiveASTVisitor doesn't guarantee lexical ordering because there are
/// some declarations, like Objective-C @implementation declarations
/// that might be represented in the AST differently to how they were written
/// in the source.
/// In particular, Objective-C @implementation declarations may contain
/// non-Objective-C declarations, like functions:
///
/// @implementation MyClass
///
/// - (void) method { }
/// void normalFunction() { }
///
/// @end
///
/// Clang's AST stores these declarations outside of the @implementation
/// declaration, so the example above would be represented using the following
/// AST:
/// |-ObjCImplementationDecl ... MyClass
/// | `-ObjCMethodDecl ... method
/// | ...
/// `-FunctionDecl ... normalFunction
/// ...
///
/// This class ensures that these declarations are traversed before the
/// corresponding TraverseDecl for the @implementation returns. This ensures
/// that the lexical parent relationship between these declarations and the
/// @implementation is preserved while traversing the AST. Note that the
/// current implementation doesn't mix these declarations with the declarations
/// contained in the @implementation, so the traversal of all of the
/// declarations in the @implementation still doesn't follow the lexical order.
template <typename Derived>
class LexicallyOrderedRecursiveASTVisitor
: public RecursiveASTVisitor<Derived> {
using BaseType = RecursiveASTVisitor<Derived>;
public:
LexicallyOrderedRecursiveASTVisitor(const SourceManager &SM) : SM(SM) {}
bool TraverseObjCImplementationDecl(ObjCImplementationDecl *D) {
// Objective-C @implementation declarations should not trigger early exit
// until the additional decls are traversed as their children are not
// lexically ordered.
bool Result = BaseType::TraverseObjCImplementationDecl(D);
return TraverseAdditionalLexicallyNestedDeclarations() ? Result : false;
}
bool TraverseObjCCategoryImplDecl(ObjCCategoryImplDecl *D) {
bool Result = BaseType::TraverseObjCCategoryImplDecl(D);
return TraverseAdditionalLexicallyNestedDeclarations() ? Result : false;
}
bool TraverseDeclContextHelper(DeclContext *DC) {
if (!DC)
return true;
for (auto I = DC->decls_begin(), E = DC->decls_end(); I != E;) {
Decl *Child = *I;
if (BaseType::canIgnoreChildDeclWhileTraversingDeclContext(Child)) {
++I;
continue;
}
if (!isa<ObjCImplementationDecl>(Child) &&
!isa<ObjCCategoryImplDecl>(Child)) {
if (!BaseType::getDerived().TraverseDecl(Child))
return false;
++I;
continue;
}
// Gather declarations that follow the Objective-C implementation
// declarations but are lexically contained in the implementation.
LexicallyNestedDeclarations.clear();
for (++I; I != E; ++I) {
Decl *Sibling = *I;
if (!SM.isBeforeInTranslationUnit(Sibling->getLocStart(),
Child->getLocEnd()))
break;
if (!BaseType::canIgnoreChildDeclWhileTraversingDeclContext(Sibling))
LexicallyNestedDeclarations.push_back(Sibling);
}
if (!BaseType::getDerived().TraverseDecl(Child))
return false;
}
return true;
}
Stmt::child_range getStmtChildren(Stmt *S) { return S->children(); }
SmallVector<Stmt *, 8> getStmtChildren(CXXOperatorCallExpr *CE) {
SmallVector<Stmt *, 8> Children(CE->children());
bool Swap;
// Switch the operator and the first operand for all infix and postfix
// operations.
switch (CE->getOperator()) {
case OO_Arrow:
case OO_Call:
case OO_Subscript:
Swap = true;
break;
case OO_PlusPlus:
case OO_MinusMinus:
// These are postfix unless there is exactly one argument.
Swap = Children.size() != 2;
break;
default:
Swap = CE->isInfixBinaryOp();
break;
}
if (Swap && Children.size() > 1)
std::swap(Children[0], Children[1]);
return Children;
}
private:
bool TraverseAdditionalLexicallyNestedDeclarations() {
// FIXME: Ideally the gathered declarations and the declarations in the
// @implementation should be mixed and sorted to get a true lexical order,
// but right now we only care about getting the correct lexical parent, so
// we can traverse the gathered nested declarations after the declarations
// in the decl context.
assert(!BaseType::getDerived().shouldTraversePostOrder() &&
"post-order traversal is not supported for lexically ordered "
"recursive ast visitor");
for (Decl *D : LexicallyNestedDeclarations) {
if (!BaseType::getDerived().TraverseDecl(D))
return false;
}
return true;
}
const SourceManager &SM;
llvm::SmallVector<Decl *, 8> LexicallyNestedDeclarations;
};
} // end namespace clang
#endif // LLVM_CLANG_AST_LEXICALLY_ORDERED_RECURSIVEASTVISITOR_H

View File

@ -1,4 +1,4 @@
//===--- NestedNameSpecifier.h - C++ nested name specifiers -----*- C++ -*-===//
//===- NestedNameSpecifier.h - C++ nested name specifiers -------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@ -11,38 +11,42 @@
// a C++ nested-name-specifier.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_AST_NESTEDNAMESPECIFIER_H
#define LLVM_CLANG_AST_NESTEDNAMESPECIFIER_H
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/Support/Compiler.h"
#include <cstdint>
#include <cstdlib>
#include <utility>
namespace clang {
class ASTContext;
class CXXRecordDecl;
class IdentifierInfo;
class LangOptions;
class NamespaceAliasDecl;
class NamespaceDecl;
class IdentifierInfo;
struct PrintingPolicy;
class Type;
class TypeLoc;
class LangOptions;
/// \brief Represents a C++ nested name specifier, such as
/// "\::std::vector<int>::".
///
/// C++ nested name specifiers are the prefixes to qualified
/// namespaces. For example, "foo::" in "foo::x" is a nested name
/// names. For example, "foo::" in "foo::x" is a nested name
/// specifier. Nested name specifiers are made up of a sequence of
/// specifiers, each of which can be a namespace, type, identifier
/// (for dependent names), decltype specifier, or the global specifier ('::').
/// The last two specifiers can only appear at the start of a
/// nested-namespace-specifier.
class NestedNameSpecifier : public llvm::FoldingSetNode {
/// \brief Enumeration describing
enum StoredSpecifierKind {
StoredIdentifier = 0,
@ -66,7 +70,7 @@ class NestedNameSpecifier : public llvm::FoldingSetNode {
/// specifier '::'. Otherwise, the pointer is one of
/// IdentifierInfo*, Namespace*, or Type*, depending on the kind of
/// specifier as encoded within the prefix.
void* Specifier;
void* Specifier = nullptr;
public:
/// \brief The kind of specifier that completes this nested name
@ -74,17 +78,23 @@ class NestedNameSpecifier : public llvm::FoldingSetNode {
enum SpecifierKind {
/// \brief An identifier, stored as an IdentifierInfo*.
Identifier,
/// \brief A namespace, stored as a NamespaceDecl*.
Namespace,
/// \brief A namespace alias, stored as a NamespaceAliasDecl*.
NamespaceAlias,
/// \brief A type, stored as a Type*.
TypeSpec,
/// \brief A type that was preceded by the 'template' keyword,
/// stored as a Type*.
TypeSpecWithTemplate,
/// \brief The global specifier '::'. There is no stored value.
Global,
/// \brief Microsoft's '__super' specifier, stored as a CXXRecordDecl* of
/// the class it appeared in.
Super
@ -92,17 +102,11 @@ class NestedNameSpecifier : public llvm::FoldingSetNode {
private:
/// \brief Builds the global specifier.
NestedNameSpecifier()
: Prefix(nullptr, StoredIdentifier), Specifier(nullptr) {}
NestedNameSpecifier() : Prefix(nullptr, StoredIdentifier) {}
/// \brief Copy constructor used internally to clone nested name
/// specifiers.
NestedNameSpecifier(const NestedNameSpecifier &Other)
: llvm::FoldingSetNode(Other), Prefix(Other.Prefix),
Specifier(Other.Specifier) {
}
void operator=(const NestedNameSpecifier &) = delete;
NestedNameSpecifier(const NestedNameSpecifier &Other) = default;
/// \brief Either find or insert the given nested name specifier
/// mockup in the given context.
@ -110,6 +114,8 @@ class NestedNameSpecifier : public llvm::FoldingSetNode {
const NestedNameSpecifier &Mockup);
public:
NestedNameSpecifier &operator=(const NestedNameSpecifier &) = delete;
/// \brief Builds a specifier combining a prefix and an identifier.
///
/// The prefix must be dependent, since nested name specifiers
@ -224,8 +230,8 @@ class NestedNameSpecifier : public llvm::FoldingSetNode {
/// \brief A C++ nested-name-specifier augmented with source location
/// information.
class NestedNameSpecifierLoc {
NestedNameSpecifier *Qualifier;
void *Data;
NestedNameSpecifier *Qualifier = nullptr;
void *Data = nullptr;
/// \brief Determines the data length for the last component in the
/// given nested-name-specifier.
@ -237,12 +243,12 @@ class NestedNameSpecifierLoc {
public:
/// \brief Construct an empty nested-name-specifier.
NestedNameSpecifierLoc() : Qualifier(nullptr), Data(nullptr) { }
NestedNameSpecifierLoc() = default;
/// \brief Construct a nested-name-specifier with source location information
/// from
NestedNameSpecifierLoc(NestedNameSpecifier *Qualifier, void *Data)
: Qualifier(Qualifier), Data(Data) { }
: Qualifier(Qualifier), Data(Data) {}
/// \brief Evalutes true when this nested-name-specifier location is
/// non-empty.
@ -339,7 +345,7 @@ class NestedNameSpecifierLoc {
class NestedNameSpecifierLocBuilder {
/// \brief The current representation of the nested-name-specifier we're
/// building.
NestedNameSpecifier *Representation;
NestedNameSpecifier *Representation = nullptr;
/// \brief Buffer used to store source-location information for the
/// nested-name-specifier.
@ -347,21 +353,18 @@ class NestedNameSpecifierLocBuilder {
/// Note that we explicitly manage the buffer (rather than using a
/// SmallVector) because \c Declarator expects it to be possible to memcpy()
/// a \c CXXScopeSpec, and CXXScopeSpec uses a NestedNameSpecifierLocBuilder.
char *Buffer;
char *Buffer = nullptr;
/// \brief The size of the buffer used to store source-location information
/// for the nested-name-specifier.
unsigned BufferSize;
unsigned BufferSize = 0;
/// \brief The capacity of the buffer used to store source-location
/// information for the nested-name-specifier.
unsigned BufferCapacity;
unsigned BufferCapacity = 0;
public:
NestedNameSpecifierLocBuilder()
: Representation(nullptr), Buffer(nullptr), BufferSize(0),
BufferCapacity(0) {}
NestedNameSpecifierLocBuilder() = default;
NestedNameSpecifierLocBuilder(const NestedNameSpecifierLocBuilder &Other);
NestedNameSpecifierLocBuilder &
@ -451,6 +454,7 @@ class NestedNameSpecifierLocBuilder {
/// \param ColonColonLoc The location of the trailing '::'.
void MakeSuper(ASTContext &Context, CXXRecordDecl *RD,
SourceLocation SuperLoc, SourceLocation ColonColonLoc);
/// \brief Make a new nested-name-specifier from incomplete source-location
/// information.
///
@ -511,6 +515,6 @@ inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
return DB;
}
}
} // namespace clang
#endif
#endif // LLVM_CLANG_AST_NESTEDNAMESPECIFIER_H

File diff suppressed because it is too large Load Diff

View File

@ -327,12 +327,13 @@ CAST_OPERATION(ZeroToOCLQueue)
// Convert a pointer to a different address space.
CAST_OPERATION(AddressSpaceConversion)
// Convert an integer initializer to an OpenCL sampler.
// Convert an integer initializer to an OpenCL sampler.
CAST_OPERATION(IntToOCLSampler)
//===- Binary Operations -------------------------------------------------===//
// Operators listed in order of precedence.
// Note that additions to this should also update the StmtVisitor class.
// Note that additions to this should also update the StmtVisitor class and
// BinaryOperator::getOverloadedOperator.
// [C++ 5.5] Pointer-to-member operators.
BINARY_OPERATION(PtrMemD, ".*")
@ -347,6 +348,8 @@ BINARY_OPERATION(Sub, "-")
// [C99 6.5.7] Bitwise shift operators.
BINARY_OPERATION(Shl, "<<")
BINARY_OPERATION(Shr, ">>")
// C++20 [expr.spaceship] Three-way comparison operator.
BINARY_OPERATION(Cmp, "<=>")
// [C99 6.5.8] Relational operators.
BINARY_OPERATION(LT, "<")
BINARY_OPERATION(GT, ">")
@ -382,7 +385,8 @@ BINARY_OPERATION(Comma, ",")
//===- Unary Operations ---------------------------------------------------===//
// Note that additions to this should also update the StmtVisitor class.
// Note that additions to this should also update the StmtVisitor class and
// UnaryOperator::getOverloadedOperator.
// [C99 6.5.2.4] Postfix increment and decrement
UNARY_OPERATION(PostInc, "++")

View File

@ -23,8 +23,6 @@ enum CastKind {
#include "clang/AST/OperationKinds.def"
};
static const CastKind CK_Invalid = static_cast<CastKind>(-1);
enum BinaryOperatorKind {
#define BINARY_OPERATION(Name, Spelling) BO_##Name,
#include "clang/AST/OperationKinds.def"

Some files were not shown because too many files have changed in this diff Show More