Compare commits
47 Commits
simple-tes
...
llvmorg-2.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
44bfe305dd | ||
|
|
d8bcd15b6c | ||
|
|
a192ae3ddf | ||
|
|
a9025246be | ||
|
|
12229cf64d | ||
|
|
f041a9ea1b | ||
|
|
811b9fd3cc | ||
|
|
11405dfab9 | ||
|
|
bc5b640c32 | ||
|
|
34b7c161ec | ||
|
|
c9dfb07f6a | ||
|
|
8c4aa724ba | ||
|
|
4ba0fad682 | ||
|
|
031126cbe4 | ||
|
|
904dbdb2d2 | ||
|
|
7792a835e1 | ||
|
|
a65abd2e95 | ||
|
|
4743d036de | ||
|
|
70236d413c | ||
|
|
fc955600a5 | ||
|
|
5d0fbabe6d | ||
|
|
0a9fff57d9 | ||
|
|
b6ca36f4bf | ||
|
|
f9b2580a93 | ||
|
|
566710097b | ||
|
|
1c1d310bb1 | ||
|
|
7f74818cec | ||
|
|
8920fde380 | ||
|
|
597ba6f9f3 | ||
|
|
dfbf3c4ca2 | ||
|
|
4821234b3a | ||
|
|
a6703a1882 | ||
|
|
154b8cdf15 | ||
|
|
d815d8fbe7 | ||
|
|
c4048b47dc | ||
|
|
67ec7f0caf | ||
|
|
7f902477a8 | ||
|
|
e378492a04 | ||
|
|
7fbd29dff2 | ||
|
|
f9827ae6e9 | ||
|
|
c302fbabd3 | ||
|
|
ee71b4169f | ||
|
|
7798616bf0 | ||
|
|
9138b324a2 | ||
|
|
f58e298792 | ||
|
|
b5be250dc5 | ||
|
|
59cccf8739 |
@@ -1,53 +0,0 @@
|
||||
macro(add_clang_library name)
|
||||
set(srcs ${ARGN})
|
||||
if(MSVC_IDE)
|
||||
file( GLOB_RECURSE headers *.h)
|
||||
set(srcs ${srcs} ${headers})
|
||||
string( REGEX MATCHALL "/[^/]+" split_path ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
list( GET split_path -1 dir)
|
||||
file( GLOB_RECURSE headers ../../include/clang${dir}/*.h)
|
||||
set(srcs ${srcs} ${headers})
|
||||
endif(MSVC_IDE)
|
||||
add_library( ${name} ${srcs} )
|
||||
if( LLVM_COMMON_DEPENDS )
|
||||
add_dependencies( ${name} ${LLVM_COMMON_DEPENDS} )
|
||||
endif( LLVM_COMMON_DEPENDS )
|
||||
if(MSVC)
|
||||
get_target_property(cflag ${name} COMPILE_FLAGS)
|
||||
if(NOT cflag)
|
||||
set(cflag "")
|
||||
endif(NOT cflag)
|
||||
set(cflag "${cflag} /Za")
|
||||
set_target_properties(${name} PROPERTIES COMPILE_FLAGS ${cflag})
|
||||
endif(MSVC)
|
||||
install(TARGETS ${name}
|
||||
LIBRARY DESTINATION lib
|
||||
ARCHIVE DESTINATION lib)
|
||||
endmacro(add_clang_library)
|
||||
|
||||
macro(add_clang_executable name)
|
||||
set(srcs ${ARGN})
|
||||
if(MSVC_IDE)
|
||||
file( GLOB_RECURSE headers *.h)
|
||||
set(srcs ${srcs} ${headers})
|
||||
endif(MSVC_IDE)
|
||||
add_llvm_executable( ${name} ${srcs} )
|
||||
install(TARGETS ${name}
|
||||
RUNTIME DESTINATION bin)
|
||||
endmacro(add_clang_executable)
|
||||
|
||||
include_directories(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include
|
||||
)
|
||||
|
||||
install(DIRECTORY include
|
||||
DESTINATION .
|
||||
PATTERN ".svn" EXCLUDE
|
||||
)
|
||||
|
||||
add_definitions( -D_GNU_SOURCE )
|
||||
|
||||
add_subdirectory(lib)
|
||||
add_subdirectory(Driver)
|
||||
|
||||
# TODO: docs.
|
||||
@@ -1,983 +0,0 @@
|
||||
//===--- ASTConsumers.cpp - ASTConsumer implementations -------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// AST Consumer Implementations.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "ASTConsumers.h"
|
||||
#include "clang/Driver/PathDiagnosticClients.h"
|
||||
#include "clang/AST/TranslationUnit.h"
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "clang/Basic/FileManager.h"
|
||||
#include "clang/AST/AST.h"
|
||||
#include "clang/AST/ASTConsumer.h"
|
||||
#include "clang/CodeGen/ModuleBuilder.h"
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/Support/Streams.h"
|
||||
#include "llvm/Support/Timer.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
using namespace clang;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// DeclPrinter - Utility class for printing top-level decls.
|
||||
|
||||
namespace {
|
||||
class DeclPrinter {
|
||||
public:
|
||||
llvm::raw_ostream& Out;
|
||||
|
||||
DeclPrinter(llvm::raw_ostream* out) : Out(out ? *out : llvm::errs()) {}
|
||||
DeclPrinter() : Out(llvm::errs()) {}
|
||||
virtual ~DeclPrinter();
|
||||
|
||||
void PrintDecl(Decl *D);
|
||||
void PrintFunctionDeclStart(FunctionDecl *FD);
|
||||
void PrintTypeDefDecl(TypedefDecl *TD);
|
||||
void PrintLinkageSpec(LinkageSpecDecl *LS);
|
||||
void PrintObjCMethodDecl(ObjCMethodDecl *OMD);
|
||||
void PrintObjCImplementationDecl(ObjCImplementationDecl *OID);
|
||||
void PrintObjCInterfaceDecl(ObjCInterfaceDecl *OID);
|
||||
void PrintObjCProtocolDecl(ObjCProtocolDecl *PID);
|
||||
void PrintObjCCategoryImplDecl(ObjCCategoryImplDecl *PID);
|
||||
void PrintObjCCategoryDecl(ObjCCategoryDecl *PID);
|
||||
void PrintObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *AID);
|
||||
void PrintObjCPropertyDecl(ObjCPropertyDecl *PD);
|
||||
void PrintObjCPropertyImplDecl(ObjCPropertyImplDecl *PID);
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
DeclPrinter::~DeclPrinter() {
|
||||
Out.flush();
|
||||
}
|
||||
|
||||
void DeclPrinter:: PrintDecl(Decl *D) {
|
||||
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
|
||||
PrintFunctionDeclStart(FD);
|
||||
|
||||
if (FD->getBody()) {
|
||||
Out << ' ';
|
||||
FD->getBody()->printPretty(Out);
|
||||
Out << '\n';
|
||||
}
|
||||
} else if (isa<ObjCMethodDecl>(D)) {
|
||||
// Do nothing, methods definitions are printed in
|
||||
// PrintObjCImplementationDecl.
|
||||
} else if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) {
|
||||
PrintTypeDefDecl(TD);
|
||||
} else if (ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(D)) {
|
||||
PrintObjCInterfaceDecl(OID);
|
||||
} else if (ObjCProtocolDecl *PID = dyn_cast<ObjCProtocolDecl>(D)) {
|
||||
PrintObjCProtocolDecl(PID);
|
||||
} else if (ObjCForwardProtocolDecl *OFPD =
|
||||
dyn_cast<ObjCForwardProtocolDecl>(D)) {
|
||||
Out << "@protocol ";
|
||||
for (unsigned i = 0, e = OFPD->getNumForwardDecls(); i != e; ++i) {
|
||||
const ObjCProtocolDecl *D = OFPD->getForwardProtocolDecl(i);
|
||||
if (i) Out << ", ";
|
||||
Out << D->getNameAsString();
|
||||
}
|
||||
Out << ";\n";
|
||||
} else if (ObjCImplementationDecl *OID =
|
||||
dyn_cast<ObjCImplementationDecl>(D)) {
|
||||
PrintObjCImplementationDecl(OID);
|
||||
} else if (ObjCCategoryImplDecl *OID =
|
||||
dyn_cast<ObjCCategoryImplDecl>(D)) {
|
||||
PrintObjCCategoryImplDecl(OID);
|
||||
} else if (ObjCCategoryDecl *OID =
|
||||
dyn_cast<ObjCCategoryDecl>(D)) {
|
||||
PrintObjCCategoryDecl(OID);
|
||||
} else if (ObjCCompatibleAliasDecl *OID =
|
||||
dyn_cast<ObjCCompatibleAliasDecl>(D)) {
|
||||
PrintObjCCompatibleAliasDecl(OID);
|
||||
} else if (ObjCClassDecl *OFCD = dyn_cast<ObjCClassDecl>(D)) {
|
||||
Out << "@class ";
|
||||
ObjCInterfaceDecl **ForwardDecls = OFCD->getForwardDecls();
|
||||
for (unsigned i = 0, e = OFCD->getNumForwardDecls(); i != e; ++i) {
|
||||
const ObjCInterfaceDecl *D = ForwardDecls[i];
|
||||
if (i) Out << ", ";
|
||||
Out << D->getNameAsString();
|
||||
}
|
||||
Out << ";\n";
|
||||
} else if (EnumDecl *ED = dyn_cast<EnumDecl>(D)) {
|
||||
Out << "enum " << ED->getNameAsString() << " {\n";
|
||||
for (EnumDecl::enumerator_iterator E = ED->enumerator_begin(),
|
||||
EEnd = ED->enumerator_end();
|
||||
E != EEnd; ++E)
|
||||
Out << " " << (*E)->getNameAsString() << ",\n";
|
||||
Out << "};\n";
|
||||
} else if (TagDecl *TD = dyn_cast<TagDecl>(D)) {
|
||||
Out << "Read top-level tag decl: '" << TD->getNameAsString() << "'\n";
|
||||
} else if (LinkageSpecDecl *LSD = dyn_cast<LinkageSpecDecl>(D)) {
|
||||
PrintLinkageSpec(LSD);
|
||||
} else if (FileScopeAsmDecl *AD = dyn_cast<FileScopeAsmDecl>(D)) {
|
||||
Out << "asm(";
|
||||
AD->getAsmString()->printPretty(Out);
|
||||
Out << ")\n";
|
||||
} else if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) {
|
||||
Out << "Read top-level variable decl: '" << ND->getNameAsString() << "'\n";
|
||||
} else {
|
||||
assert(0 && "Unknown decl type!");
|
||||
}
|
||||
}
|
||||
|
||||
void DeclPrinter::PrintFunctionDeclStart(FunctionDecl *FD) {
|
||||
bool HasBody = FD->getBody();
|
||||
|
||||
Out << '\n';
|
||||
|
||||
switch (FD->getStorageClass()) {
|
||||
default: assert(0 && "Unknown storage class");
|
||||
case FunctionDecl::None: break;
|
||||
case FunctionDecl::Extern: Out << "extern "; break;
|
||||
case FunctionDecl::Static: Out << "static "; break;
|
||||
case FunctionDecl::PrivateExtern: Out << "__private_extern__ "; break;
|
||||
}
|
||||
|
||||
if (FD->isInline())
|
||||
Out << "inline ";
|
||||
|
||||
std::string Proto = FD->getNameAsString();
|
||||
const FunctionType *AFT = FD->getType()->getAsFunctionType();
|
||||
|
||||
if (const FunctionTypeProto *FT = dyn_cast<FunctionTypeProto>(AFT)) {
|
||||
Proto += "(";
|
||||
for (unsigned i = 0, e = FD->getNumParams(); i != e; ++i) {
|
||||
if (i) Proto += ", ";
|
||||
std::string ParamStr;
|
||||
if (HasBody) ParamStr = FD->getParamDecl(i)->getNameAsString();
|
||||
|
||||
FT->getArgType(i).getAsStringInternal(ParamStr);
|
||||
Proto += ParamStr;
|
||||
}
|
||||
|
||||
if (FT->isVariadic()) {
|
||||
if (FD->getNumParams()) Proto += ", ";
|
||||
Proto += "...";
|
||||
}
|
||||
Proto += ")";
|
||||
} else {
|
||||
assert(isa<FunctionTypeNoProto>(AFT));
|
||||
Proto += "()";
|
||||
}
|
||||
|
||||
AFT->getResultType().getAsStringInternal(Proto);
|
||||
Out << Proto;
|
||||
|
||||
if (!FD->getBody())
|
||||
Out << ";\n";
|
||||
// Doesn't print the body.
|
||||
}
|
||||
|
||||
void DeclPrinter::PrintTypeDefDecl(TypedefDecl *TD) {
|
||||
std::string S = TD->getNameAsString();
|
||||
TD->getUnderlyingType().getAsStringInternal(S);
|
||||
Out << "typedef " << S << ";\n";
|
||||
}
|
||||
|
||||
void DeclPrinter::PrintLinkageSpec(LinkageSpecDecl *LS) {
|
||||
const char *l;
|
||||
if (LS->getLanguage() == LinkageSpecDecl::lang_c)
|
||||
l = "C";
|
||||
else {
|
||||
assert(LS->getLanguage() == LinkageSpecDecl::lang_cxx &&
|
||||
"unknown language in linkage specification");
|
||||
l = "C++";
|
||||
}
|
||||
|
||||
Out << "extern \"" << l << "\" ";
|
||||
if (LS->hasBraces())
|
||||
Out << "{\n";
|
||||
|
||||
for (LinkageSpecDecl::decl_iterator D = LS->decls_begin(),
|
||||
DEnd = LS->decls_end();
|
||||
D != DEnd; ++D)
|
||||
PrintDecl(*D);
|
||||
|
||||
if (LS->hasBraces())
|
||||
Out << "}";
|
||||
Out << "\n";
|
||||
}
|
||||
|
||||
void DeclPrinter::PrintObjCMethodDecl(ObjCMethodDecl *OMD) {
|
||||
if (OMD->isInstanceMethod())
|
||||
Out << "\n- ";
|
||||
else
|
||||
Out << "\n+ ";
|
||||
if (!OMD->getResultType().isNull())
|
||||
Out << '(' << OMD->getResultType().getAsString() << ")";
|
||||
|
||||
std::string name = OMD->getSelector().getAsString();
|
||||
std::string::size_type pos, lastPos = 0;
|
||||
for (unsigned i = 0, e = OMD->getNumParams(); i != e; ++i) {
|
||||
ParmVarDecl *PDecl = OMD->getParamDecl(i);
|
||||
// FIXME: selector is missing here!
|
||||
pos = name.find_first_of(":", lastPos);
|
||||
Out << " " << name.substr(lastPos, pos - lastPos);
|
||||
Out << ":(" << PDecl->getType().getAsString() << ")"
|
||||
<< PDecl->getNameAsString();
|
||||
lastPos = pos + 1;
|
||||
}
|
||||
|
||||
if (OMD->getNumParams() == 0)
|
||||
Out << " " << name;
|
||||
|
||||
if (OMD->isVariadic())
|
||||
Out << ", ...";
|
||||
|
||||
Out << ";";
|
||||
}
|
||||
|
||||
void DeclPrinter::PrintObjCImplementationDecl(ObjCImplementationDecl *OID) {
|
||||
std::string I = OID->getNameAsString();
|
||||
ObjCInterfaceDecl *SID = OID->getSuperClass();
|
||||
|
||||
if (SID)
|
||||
Out << "@implementation " << I << " : " << SID->getNameAsString();
|
||||
else
|
||||
Out << "@implementation " << I;
|
||||
|
||||
for (ObjCImplementationDecl::instmeth_iterator I = OID->instmeth_begin(),
|
||||
E = OID->instmeth_end(); I != E; ++I) {
|
||||
ObjCMethodDecl *OMD = *I;
|
||||
PrintObjCMethodDecl(OMD);
|
||||
if (OMD->getBody()) {
|
||||
Out << ' ';
|
||||
OMD->getBody()->printPretty(Out);
|
||||
Out << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
for (ObjCImplementationDecl::classmeth_iterator I = OID->classmeth_begin(),
|
||||
E = OID->classmeth_end(); I != E; ++I) {
|
||||
ObjCMethodDecl *OMD = *I;
|
||||
PrintObjCMethodDecl(OMD);
|
||||
if (OMD->getBody()) {
|
||||
Out << ' ';
|
||||
OMD->getBody()->printPretty(Out);
|
||||
Out << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
for (ObjCImplementationDecl::propimpl_iterator I = OID->propimpl_begin(),
|
||||
E = OID->propimpl_end(); I != E; ++I)
|
||||
PrintObjCPropertyImplDecl(*I);
|
||||
|
||||
Out << "@end\n";
|
||||
}
|
||||
|
||||
|
||||
void DeclPrinter::PrintObjCInterfaceDecl(ObjCInterfaceDecl *OID) {
|
||||
std::string I = OID->getNameAsString();
|
||||
ObjCInterfaceDecl *SID = OID->getSuperClass();
|
||||
|
||||
if (SID)
|
||||
Out << "@interface " << I << " : " << SID->getNameAsString();
|
||||
else
|
||||
Out << "@interface " << I;
|
||||
|
||||
// Protocols?
|
||||
const ObjCList<ObjCProtocolDecl> &Protocols = OID->getReferencedProtocols();
|
||||
if (!Protocols.empty()) {
|
||||
for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),
|
||||
E = Protocols.end(); I != E; ++I)
|
||||
Out << (I == Protocols.begin() ? '<' : ',') << (*I)->getNameAsString();
|
||||
}
|
||||
|
||||
if (!Protocols.empty())
|
||||
Out << ">";
|
||||
Out << '\n';
|
||||
|
||||
if (OID->ivar_size() > 0) {
|
||||
Out << '{';
|
||||
for (ObjCInterfaceDecl::ivar_iterator I = OID->ivar_begin(),
|
||||
E = OID->ivar_end(); I != E; ++I) {
|
||||
Out << '\t' << (*I)->getType().getAsString()
|
||||
<< ' ' << (*I)->getNameAsString() << ";\n";
|
||||
}
|
||||
Out << "}\n";
|
||||
}
|
||||
|
||||
for (ObjCInterfaceDecl::prop_iterator I = OID->prop_begin(),
|
||||
E = OID->prop_end(); I != E; ++I)
|
||||
PrintObjCPropertyDecl(*I);
|
||||
bool eol_needed = false;
|
||||
for (ObjCInterfaceDecl::classmeth_iterator I = OID->classmeth_begin(),
|
||||
E = OID->classmeth_end(); I != E; ++I)
|
||||
eol_needed = true, PrintObjCMethodDecl(*I);
|
||||
|
||||
for (ObjCInterfaceDecl::instmeth_iterator I = OID->instmeth_begin(),
|
||||
E = OID->instmeth_end(); I != E; ++I)
|
||||
eol_needed = true, PrintObjCMethodDecl(*I);
|
||||
|
||||
Out << (eol_needed ? "\n@end\n" : "@end\n");
|
||||
// FIXME: implement the rest...
|
||||
}
|
||||
|
||||
void DeclPrinter::PrintObjCProtocolDecl(ObjCProtocolDecl *PID) {
|
||||
Out << "@protocol " << PID->getNameAsString() << '\n';
|
||||
|
||||
for (ObjCProtocolDecl::prop_iterator I = PID->prop_begin(),
|
||||
E = PID->prop_end(); I != E; ++I)
|
||||
PrintObjCPropertyDecl(*I);
|
||||
Out << "@end\n";
|
||||
// FIXME: implement the rest...
|
||||
}
|
||||
|
||||
void DeclPrinter::PrintObjCCategoryImplDecl(ObjCCategoryImplDecl *PID) {
|
||||
Out << "@implementation "
|
||||
<< PID->getClassInterface()->getNameAsString()
|
||||
<< '(' << PID->getNameAsString() << ");\n";
|
||||
for (ObjCCategoryImplDecl::propimpl_iterator I = PID->propimpl_begin(),
|
||||
E = PID->propimpl_end(); I != E; ++I)
|
||||
PrintObjCPropertyImplDecl(*I);
|
||||
Out << "@end\n";
|
||||
// FIXME: implement the rest...
|
||||
}
|
||||
|
||||
void DeclPrinter::PrintObjCCategoryDecl(ObjCCategoryDecl *PID) {
|
||||
Out << "@interface "
|
||||
<< PID->getClassInterface()->getNameAsString()
|
||||
<< '(' << PID->getNameAsString() << ");\n";
|
||||
// Output property declarations.
|
||||
for (ObjCCategoryDecl::prop_iterator I = PID->prop_begin(),
|
||||
E = PID->prop_end(); I != E; ++I)
|
||||
PrintObjCPropertyDecl(*I);
|
||||
Out << "@end\n";
|
||||
|
||||
// FIXME: implement the rest...
|
||||
}
|
||||
|
||||
void DeclPrinter::PrintObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *AID) {
|
||||
Out << "@compatibility_alias " << AID->getNameAsString()
|
||||
<< ' ' << AID->getClassInterface()->getNameAsString() << ";\n";
|
||||
}
|
||||
|
||||
/// PrintObjCPropertyDecl - print a property declaration.
|
||||
///
|
||||
void DeclPrinter::PrintObjCPropertyDecl(ObjCPropertyDecl *PDecl) {
|
||||
if (PDecl->getPropertyImplementation() == ObjCPropertyDecl::Required)
|
||||
Out << "@required\n";
|
||||
else if (PDecl->getPropertyImplementation() == ObjCPropertyDecl::Optional)
|
||||
Out << "@optional\n";
|
||||
|
||||
Out << "@property";
|
||||
if (PDecl->getPropertyAttributes() != ObjCPropertyDecl::OBJC_PR_noattr) {
|
||||
bool first = true;
|
||||
Out << " (";
|
||||
if (PDecl->getPropertyAttributes() &
|
||||
ObjCPropertyDecl::OBJC_PR_readonly) {
|
||||
Out << (first ? ' ' : ',') << "readonly";
|
||||
first = false;
|
||||
}
|
||||
|
||||
if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_getter) {
|
||||
Out << (first ? ' ' : ',') << "getter = "
|
||||
<< PDecl->getGetterName().getAsString();
|
||||
first = false;
|
||||
}
|
||||
if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_setter) {
|
||||
Out << (first ? ' ' : ',') << "setter = "
|
||||
<< PDecl->getSetterName().getAsString();
|
||||
first = false;
|
||||
}
|
||||
|
||||
if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_assign) {
|
||||
Out << (first ? ' ' : ',') << "assign";
|
||||
first = false;
|
||||
}
|
||||
|
||||
if (PDecl->getPropertyAttributes() &
|
||||
ObjCPropertyDecl::OBJC_PR_readwrite) {
|
||||
Out << (first ? ' ' : ',') << "readwrite";
|
||||
first = false;
|
||||
}
|
||||
|
||||
if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_retain) {
|
||||
Out << (first ? ' ' : ',') << "retain";
|
||||
first = false;
|
||||
}
|
||||
|
||||
if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_copy) {
|
||||
Out << (first ? ' ' : ',') << "copy";
|
||||
first = false;
|
||||
}
|
||||
|
||||
if (PDecl->getPropertyAttributes() &
|
||||
ObjCPropertyDecl::OBJC_PR_nonatomic) {
|
||||
Out << (first ? ' ' : ',') << "nonatomic";
|
||||
first = false;
|
||||
}
|
||||
Out << " )";
|
||||
}
|
||||
Out << ' ' << PDecl->getType().getAsString()
|
||||
<< ' ' << PDecl->getNameAsString();
|
||||
|
||||
Out << ";\n";
|
||||
}
|
||||
|
||||
/// PrintObjCPropertyImplDecl - Print an objective-c property implementation
|
||||
/// declaration syntax.
|
||||
///
|
||||
void DeclPrinter::PrintObjCPropertyImplDecl(ObjCPropertyImplDecl *PID) {
|
||||
if (PID->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize)
|
||||
Out << "\n@synthesize ";
|
||||
else
|
||||
Out << "\n@dynamic ";
|
||||
Out << PID->getPropertyDecl()->getNameAsString();
|
||||
if (PID->getPropertyIvarDecl())
|
||||
Out << "=" << PID->getPropertyIvarDecl()->getNameAsString();
|
||||
Out << ";\n";
|
||||
}
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// ASTPrinter - Pretty-printer of ASTs
|
||||
|
||||
namespace {
|
||||
class ASTPrinter : public ASTConsumer, public DeclPrinter {
|
||||
public:
|
||||
ASTPrinter(llvm::raw_ostream* o = NULL) : DeclPrinter(o) {}
|
||||
|
||||
virtual void HandleTopLevelDecl(Decl *D) {
|
||||
PrintDecl(D);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
ASTConsumer *clang::CreateASTPrinter(llvm::raw_ostream* out) {
|
||||
return new ASTPrinter(out);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// ASTDumper - Low-level dumper of ASTs
|
||||
|
||||
namespace {
|
||||
class ASTDumper : public ASTConsumer, public DeclPrinter {
|
||||
SourceManager *SM;
|
||||
public:
|
||||
ASTDumper() : DeclPrinter() {}
|
||||
|
||||
void Initialize(ASTContext &Context) {
|
||||
SM = &Context.getSourceManager();
|
||||
}
|
||||
|
||||
virtual void HandleTopLevelDecl(Decl *D) {
|
||||
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
|
||||
PrintFunctionDeclStart(FD);
|
||||
|
||||
if (FD->getBody()) {
|
||||
Out << '\n';
|
||||
// FIXME: convert dumper to use std::ostream?
|
||||
FD->getBody()->dumpAll(*SM);
|
||||
Out << '\n';
|
||||
}
|
||||
} else if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) {
|
||||
PrintTypeDefDecl(TD);
|
||||
} else if (ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(D)) {
|
||||
Out << "Read objc interface '" << OID->getNameAsString() << "'\n";
|
||||
} else if (ObjCProtocolDecl *OPD = dyn_cast<ObjCProtocolDecl>(D)) {
|
||||
Out << "Read objc protocol '" << OPD->getNameAsString() << "'\n";
|
||||
} else if (ObjCCategoryDecl *OCD = dyn_cast<ObjCCategoryDecl>(D)) {
|
||||
Out << "Read objc category '" << OCD->getNameAsString() << "'\n";
|
||||
} else if (isa<ObjCForwardProtocolDecl>(D)) {
|
||||
Out << "Read objc fwd protocol decl\n";
|
||||
} else if (isa<ObjCClassDecl>(D)) {
|
||||
Out << "Read objc fwd class decl\n";
|
||||
} else if (isa<FileScopeAsmDecl>(D)) {
|
||||
Out << "Read file scope asm decl\n";
|
||||
} else if (ObjCMethodDecl* MD = dyn_cast<ObjCMethodDecl>(D)) {
|
||||
Out << "Read objc method decl: '" << MD->getSelector().getAsString()
|
||||
<< "'\n";
|
||||
if (MD->getBody()) {
|
||||
// FIXME: convert dumper to use std::ostream?
|
||||
MD->getBody()->dumpAll(*SM);
|
||||
Out << '\n';
|
||||
}
|
||||
} else if (isa<ObjCImplementationDecl>(D)) {
|
||||
Out << "Read objc implementation decl\n";
|
||||
} else if (isa<ObjCCategoryImplDecl>(D)) {
|
||||
Out << "Read objc category implementation decl\n";
|
||||
} else if (isa<LinkageSpecDecl>(D)) {
|
||||
Out << "Read linkage spec decl\n";
|
||||
} else if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) {
|
||||
Out << "Read top-level variable decl: '" << ND->getNameAsString()
|
||||
<< "'\n";
|
||||
} else {
|
||||
assert(0 && "Unknown decl type!");
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
ASTConsumer *clang::CreateASTDumper() { return new ASTDumper(); }
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// ASTViewer - AST Visualization
|
||||
|
||||
namespace {
|
||||
class ASTViewer : public ASTConsumer {
|
||||
SourceManager *SM;
|
||||
public:
|
||||
void Initialize(ASTContext &Context) {
|
||||
SM = &Context.getSourceManager();
|
||||
}
|
||||
|
||||
virtual void HandleTopLevelDecl(Decl *D) {
|
||||
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
|
||||
DeclPrinter().PrintFunctionDeclStart(FD);
|
||||
|
||||
if (FD->getBody()) {
|
||||
llvm::cerr << '\n';
|
||||
FD->getBody()->viewAST();
|
||||
llvm::cerr << '\n';
|
||||
}
|
||||
}
|
||||
else if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
|
||||
DeclPrinter().PrintObjCMethodDecl(MD);
|
||||
|
||||
if (MD->getBody()) {
|
||||
llvm::cerr << '\n';
|
||||
MD->getBody()->viewAST();
|
||||
llvm::cerr << '\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
ASTConsumer *clang::CreateASTViewer() { return new ASTViewer(); }
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// DeclContextPrinter - Decl and DeclContext Visualization
|
||||
|
||||
namespace {
|
||||
|
||||
class DeclContextPrinter : public ASTConsumer {
|
||||
llvm::raw_ostream& Out;
|
||||
public:
|
||||
DeclContextPrinter() : Out(llvm::errs()) {}
|
||||
|
||||
void HandleTranslationUnit(TranslationUnit& TU) {
|
||||
TranslationUnitDecl* TUD = TU.getContext().getTranslationUnitDecl();
|
||||
PrintDeclContext(TUD, 4);
|
||||
}
|
||||
|
||||
void PrintDeclContext(const DeclContext* DC, unsigned Indentation);
|
||||
};
|
||||
|
||||
void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
|
||||
unsigned Indentation) {
|
||||
// Print DeclContext name.
|
||||
switch (DC->getDeclKind()) {
|
||||
case Decl::TranslationUnit:
|
||||
Out << "[translation unit] " << DC;
|
||||
break;
|
||||
case Decl::Namespace: {
|
||||
Out << "[namespace] ";
|
||||
NamespaceDecl* ND = NamespaceDecl::castFromDeclContext(DC);
|
||||
Out << ND->getNameAsString();
|
||||
break;
|
||||
}
|
||||
case Decl::Enum: {
|
||||
EnumDecl* ED = EnumDecl::castFromDeclContext(DC);
|
||||
if (ED->isDefinition())
|
||||
Out << "[enum] ";
|
||||
else
|
||||
Out << "<enum> ";
|
||||
Out << ED->getNameAsString();
|
||||
break;
|
||||
}
|
||||
case Decl::Record: {
|
||||
RecordDecl* RD = RecordDecl::castFromDeclContext(DC);
|
||||
if (RD->isDefinition())
|
||||
Out << "[struct] ";
|
||||
else
|
||||
Out << "<struct> ";
|
||||
Out << RD->getNameAsString();
|
||||
break;
|
||||
}
|
||||
case Decl::CXXRecord: {
|
||||
CXXRecordDecl* RD = CXXRecordDecl::castFromDeclContext(DC);
|
||||
if (RD->isDefinition())
|
||||
Out << "[class] ";
|
||||
else
|
||||
Out << "<class> ";
|
||||
Out << RD->getNameAsString() << " " << DC;
|
||||
break;
|
||||
}
|
||||
case Decl::ObjCMethod:
|
||||
Out << "[objc method]";
|
||||
break;
|
||||
case Decl::ObjCInterface:
|
||||
Out << "[objc interface]";
|
||||
break;
|
||||
case Decl::ObjCCategory:
|
||||
Out << "[objc category]";
|
||||
break;
|
||||
case Decl::ObjCProtocol:
|
||||
Out << "[objc protocol]";
|
||||
break;
|
||||
case Decl::ObjCImplementation:
|
||||
Out << "[objc implementation]";
|
||||
break;
|
||||
case Decl::ObjCCategoryImpl:
|
||||
Out << "[objc categoryimpl]";
|
||||
break;
|
||||
case Decl::LinkageSpec:
|
||||
Out << "[linkage spec]";
|
||||
break;
|
||||
case Decl::Block:
|
||||
Out << "[block]";
|
||||
break;
|
||||
case Decl::Function: {
|
||||
FunctionDecl* FD = FunctionDecl::castFromDeclContext(DC);
|
||||
if (FD->isThisDeclarationADefinition())
|
||||
Out << "[function] ";
|
||||
else
|
||||
Out << "<function> ";
|
||||
Out << FD->getNameAsString();
|
||||
// Print the parameters.
|
||||
Out << "(";
|
||||
bool PrintComma = false;
|
||||
for (FunctionDecl::param_const_iterator I = FD->param_begin(),
|
||||
E = FD->param_end(); I != E; ++I) {
|
||||
if (PrintComma)
|
||||
Out << ", ";
|
||||
else
|
||||
PrintComma = true;
|
||||
Out << (*I)->getNameAsString();
|
||||
}
|
||||
Out << ")";
|
||||
break;
|
||||
}
|
||||
case Decl::CXXMethod: {
|
||||
CXXMethodDecl* D = CXXMethodDecl::castFromDeclContext(DC);
|
||||
if (D->isOutOfLineDefinition())
|
||||
Out << "[c++ method] ";
|
||||
else if (D->isImplicit())
|
||||
Out << "(c++ method) ";
|
||||
else
|
||||
Out << "<c++ method> ";
|
||||
Out << D->getNameAsString();
|
||||
// Print the parameters.
|
||||
Out << "(";
|
||||
bool PrintComma = false;
|
||||
for (FunctionDecl::param_const_iterator I = D->param_begin(),
|
||||
E = D->param_end(); I != E; ++I) {
|
||||
if (PrintComma)
|
||||
Out << ", ";
|
||||
else
|
||||
PrintComma = true;
|
||||
Out << (*I)->getNameAsString();
|
||||
}
|
||||
Out << ")";
|
||||
|
||||
// Check the semantic DeclContext.
|
||||
DeclContext* SemaDC = D->getDeclContext();
|
||||
DeclContext* LexicalDC = D->getLexicalDeclContext();
|
||||
if (SemaDC != LexicalDC)
|
||||
Out << " [[" << SemaDC << "]]";
|
||||
|
||||
break;
|
||||
}
|
||||
case Decl::CXXConstructor: {
|
||||
CXXConstructorDecl* D = CXXConstructorDecl::castFromDeclContext(DC);
|
||||
if (D->isOutOfLineDefinition())
|
||||
Out << "[c++ ctor] ";
|
||||
else if (D->isImplicit())
|
||||
Out << "(c++ ctor) ";
|
||||
else
|
||||
Out << "<c++ ctor> ";
|
||||
Out << D->getNameAsString();
|
||||
// Print the parameters.
|
||||
Out << "(";
|
||||
bool PrintComma = false;
|
||||
for (FunctionDecl::param_const_iterator I = D->param_begin(),
|
||||
E = D->param_end(); I != E; ++I) {
|
||||
if (PrintComma)
|
||||
Out << ", ";
|
||||
else
|
||||
PrintComma = true;
|
||||
Out << (*I)->getNameAsString();
|
||||
}
|
||||
Out << ")";
|
||||
|
||||
// Check the semantic DC.
|
||||
DeclContext* SemaDC = D->getDeclContext();
|
||||
DeclContext* LexicalDC = D->getLexicalDeclContext();
|
||||
if (SemaDC != LexicalDC)
|
||||
Out << " [[" << SemaDC << "]]";
|
||||
break;
|
||||
}
|
||||
case Decl::CXXDestructor: {
|
||||
CXXDestructorDecl* D = CXXDestructorDecl::castFromDeclContext(DC);
|
||||
if (D->isOutOfLineDefinition())
|
||||
Out << "[c++ dtor] ";
|
||||
else if (D->isImplicit())
|
||||
Out << "(c++ dtor) ";
|
||||
else
|
||||
Out << "<c++ dtor> ";
|
||||
Out << D->getNameAsString();
|
||||
// Check the semantic DC.
|
||||
DeclContext* SemaDC = D->getDeclContext();
|
||||
DeclContext* LexicalDC = D->getLexicalDeclContext();
|
||||
if (SemaDC != LexicalDC)
|
||||
Out << " [[" << SemaDC << "]]";
|
||||
break;
|
||||
}
|
||||
case Decl::CXXConversion: {
|
||||
CXXConversionDecl* D = CXXConversionDecl::castFromDeclContext(DC);
|
||||
if (D->isOutOfLineDefinition())
|
||||
Out << "[c++ conversion] ";
|
||||
else if (D->isImplicit())
|
||||
Out << "(c++ conversion) ";
|
||||
else
|
||||
Out << "<c++ conversion> ";
|
||||
Out << D->getNameAsString();
|
||||
// Check the semantic DC.
|
||||
DeclContext* SemaDC = D->getDeclContext();
|
||||
DeclContext* LexicalDC = D->getLexicalDeclContext();
|
||||
if (SemaDC != LexicalDC)
|
||||
Out << " [[" << SemaDC << "]]";
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
assert(0 && "a decl that inherits DeclContext isn't handled");
|
||||
}
|
||||
|
||||
Out << "\n";
|
||||
|
||||
// Print decls in the DeclContext.
|
||||
for (DeclContext::decl_iterator I = DC->decls_begin(), E = DC->decls_end();
|
||||
I != E; ++I) {
|
||||
for (unsigned i = 0; i < Indentation; ++i)
|
||||
Out << " ";
|
||||
|
||||
Decl::Kind DK = I->getKind();
|
||||
switch (DK) {
|
||||
case Decl::Namespace:
|
||||
case Decl::Enum:
|
||||
case Decl::Record:
|
||||
case Decl::CXXRecord:
|
||||
case Decl::ObjCMethod:
|
||||
case Decl::ObjCInterface:
|
||||
case Decl::ObjCCategory:
|
||||
case Decl::ObjCProtocol:
|
||||
case Decl::ObjCImplementation:
|
||||
case Decl::ObjCCategoryImpl:
|
||||
case Decl::LinkageSpec:
|
||||
case Decl::Block:
|
||||
case Decl::Function:
|
||||
case Decl::CXXMethod:
|
||||
case Decl::CXXConstructor:
|
||||
case Decl::CXXDestructor:
|
||||
case Decl::CXXConversion:
|
||||
{
|
||||
DeclContext* DC = Decl::castToDeclContext(*I);
|
||||
PrintDeclContext(DC, Indentation+4);
|
||||
break;
|
||||
}
|
||||
case Decl::Field: {
|
||||
FieldDecl* FD = cast<FieldDecl>(*I);
|
||||
Out << "<field> " << FD->getNameAsString() << "\n";
|
||||
break;
|
||||
}
|
||||
case Decl::Typedef: {
|
||||
TypedefDecl* TD = cast<TypedefDecl>(*I);
|
||||
Out << "<typedef> " << TD->getNameAsString() << "\n";
|
||||
break;
|
||||
}
|
||||
case Decl::EnumConstant: {
|
||||
EnumConstantDecl* ECD = cast<EnumConstantDecl>(*I);
|
||||
Out << "<enum constant> " << ECD->getNameAsString() << "\n";
|
||||
break;
|
||||
}
|
||||
case Decl::Var: {
|
||||
VarDecl* VD = cast<VarDecl>(*I);
|
||||
Out << "<var> " << VD->getNameAsString() << "\n";
|
||||
break;
|
||||
}
|
||||
case Decl::ImplicitParam: {
|
||||
ImplicitParamDecl* IPD = cast<ImplicitParamDecl>(*I);
|
||||
Out << "<implicit parameter> " << IPD->getNameAsString() << "\n";
|
||||
break;
|
||||
}
|
||||
case Decl::CXXClassVar: {
|
||||
CXXClassVarDecl* CVD = cast<CXXClassVarDecl>(*I);
|
||||
Out << "<static member var> " << CVD->getNameAsString() << "\n";
|
||||
break;
|
||||
}
|
||||
case Decl::ParmVar: {
|
||||
ParmVarDecl* PVD = cast<ParmVarDecl>(*I);
|
||||
Out << "<parameter> " << PVD->getNameAsString() << "\n";
|
||||
break;
|
||||
}
|
||||
case Decl::ObjCProperty: {
|
||||
ObjCPropertyDecl* OPD = cast<ObjCPropertyDecl>(*I);
|
||||
Out << "<objc property> " << OPD->getNameAsString() << "\n";
|
||||
break;
|
||||
}
|
||||
default:
|
||||
fprintf(stderr, "DeclKind: %d\n", DK);
|
||||
assert(0 && "decl unhandled");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ASTConsumer *clang::CreateDeclContextPrinter() {
|
||||
return new DeclContextPrinter();
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// InheritanceViewer - C++ Inheritance Visualization
|
||||
|
||||
namespace {
|
||||
class InheritanceViewer : public ASTConsumer {
|
||||
const std::string clsname;
|
||||
public:
|
||||
InheritanceViewer(const std::string& cname) : clsname(cname) {}
|
||||
|
||||
void HandleTranslationUnit(TranslationUnit& TU) {
|
||||
ASTContext& C = TU.getContext();
|
||||
for (ASTContext::type_iterator I=C.types_begin(),E=C.types_end(); I!=E; ++I)
|
||||
if (CXXRecordType *T = dyn_cast<CXXRecordType>(*I)) {
|
||||
CXXRecordDecl* D = T->getDecl();
|
||||
// FIXME: This lookup needs to be generalized to handle namespaces and
|
||||
// (when we support them) templates.
|
||||
if (D->getNameAsString() == clsname) {
|
||||
D->viewInheritance(C);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
ASTConsumer *clang::CreateInheritanceViewer(const std::string& clsname) {
|
||||
return new InheritanceViewer(clsname);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// AST Serializer
|
||||
|
||||
namespace {
|
||||
|
||||
class ASTSerializer : public ASTConsumer {
|
||||
protected:
|
||||
Diagnostic& Diags;
|
||||
|
||||
public:
|
||||
ASTSerializer(Diagnostic& diags) : Diags(diags) {}
|
||||
};
|
||||
|
||||
class SingleFileSerializer : public ASTSerializer {
|
||||
const llvm::sys::Path FName;
|
||||
public:
|
||||
SingleFileSerializer(const llvm::sys::Path& F, Diagnostic& diags)
|
||||
: ASTSerializer(diags), FName(F) {}
|
||||
|
||||
virtual void HandleTranslationUnit(TranslationUnit& TU) {
|
||||
if (Diags.hasErrorOccurred())
|
||||
return;
|
||||
EmitASTBitcodeFile(&TU, FName);
|
||||
}
|
||||
};
|
||||
|
||||
class BuildSerializer : public ASTSerializer {
|
||||
llvm::sys::Path EmitDir;
|
||||
public:
|
||||
BuildSerializer(const llvm::sys::Path& dir, Diagnostic& diags)
|
||||
: ASTSerializer(diags), EmitDir(dir) {}
|
||||
|
||||
virtual void HandleTranslationUnit(TranslationUnit& TU) {
|
||||
if (Diags.hasErrorOccurred())
|
||||
return;
|
||||
|
||||
SourceManager& SourceMgr = TU.getContext().getSourceManager();
|
||||
FileID ID = SourceMgr.getMainFileID();
|
||||
assert(!ID.isInvalid() && "MainFileID not set!");
|
||||
const FileEntry* FE = SourceMgr.getFileEntryForID(ID);
|
||||
assert(FE && "No FileEntry for main file.");
|
||||
|
||||
// FIXME: This is not portable to Windows.
|
||||
// FIXME: This logic should probably be moved elsewhere later.
|
||||
|
||||
llvm::sys::Path FName(EmitDir);
|
||||
|
||||
std::vector<char> buf;
|
||||
buf.reserve(strlen(FE->getName())+100);
|
||||
|
||||
sprintf(&buf[0], "dev_%llx", (uint64_t) FE->getDevice());
|
||||
FName.appendComponent(&buf[0]);
|
||||
FName.createDirectoryOnDisk(true);
|
||||
if (!FName.canWrite() || !FName.isDirectory()) {
|
||||
assert (false && "Could not create 'device' serialization directory.");
|
||||
return;
|
||||
}
|
||||
|
||||
sprintf(&buf[0], "%s-%llX.ast", FE->getName(), (uint64_t) FE->getInode());
|
||||
FName.appendComponent(&buf[0]);
|
||||
EmitASTBitcodeFile(&TU, FName);
|
||||
|
||||
// Now emit the sources.
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
|
||||
ASTConsumer* clang::CreateASTSerializer(const std::string& InFile,
|
||||
const std::string& OutputFile,
|
||||
Diagnostic &Diags) {
|
||||
|
||||
if (OutputFile.size()) {
|
||||
if (InFile == "-") {
|
||||
llvm::cerr <<
|
||||
"error: Cannot use --serialize with -o for source read from STDIN.\n";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// The user specified an AST-emission directory. Determine if the path
|
||||
// is absolute.
|
||||
llvm::sys::Path EmitDir(OutputFile);
|
||||
|
||||
if (!EmitDir.isAbsolute()) {
|
||||
llvm::cerr <<
|
||||
"error: Output directory for --serialize must be an absolute path.\n";
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Create the directory if it does not exist.
|
||||
EmitDir.createDirectoryOnDisk(true);
|
||||
if (!EmitDir.canWrite() || !EmitDir.isDirectory()) {
|
||||
llvm::cerr <<
|
||||
"error: Could not create output directory for --serialize.\n";
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// FIXME: We should probably only allow using BuildSerializer when
|
||||
// the ASTs come from parsed source files, and not from .ast files.
|
||||
return new BuildSerializer(EmitDir, Diags);
|
||||
}
|
||||
|
||||
// The user did not specify an output directory for serialized ASTs.
|
||||
// Serialize the translation to a single file whose name is the same
|
||||
// as the input file with the ".ast" extension appended.
|
||||
|
||||
llvm::sys::Path FName(InFile.c_str());
|
||||
FName.appendSuffix("ast");
|
||||
return new SingleFileSerializer(FName, Diags);
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
//===--- ASTConsumers.h - ASTConsumer implementations -----------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// AST Consumers.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef DRIVER_ASTCONSUMERS_H
|
||||
#define DRIVER_ASTCONSUMERS_H
|
||||
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <string>
|
||||
#include <iosfwd>
|
||||
|
||||
namespace llvm {
|
||||
class Module;
|
||||
namespace sys { class Path; }
|
||||
}
|
||||
namespace clang {
|
||||
|
||||
class ASTConsumer;
|
||||
class Diagnostic;
|
||||
class FileManager;
|
||||
class Preprocessor;
|
||||
class PreprocessorFactory;
|
||||
struct CompileOptions;
|
||||
struct LangOptions;
|
||||
|
||||
ASTConsumer *CreateASTPrinter(llvm::raw_ostream* OS = NULL);
|
||||
|
||||
ASTConsumer *CreateASTDumper();
|
||||
|
||||
ASTConsumer *CreateASTViewer();
|
||||
|
||||
ASTConsumer *CreateDeclContextPrinter();
|
||||
|
||||
ASTConsumer *CreateCodeRewriterTest(const std::string& InFile,
|
||||
const std::string& OutFile,
|
||||
Diagnostic &Diags,
|
||||
const LangOptions &LOpts);
|
||||
|
||||
enum BackendAction {
|
||||
Backend_EmitAssembly,
|
||||
Backend_EmitBC,
|
||||
Backend_EmitLL
|
||||
};
|
||||
ASTConsumer *CreateBackendConsumer(BackendAction Action,
|
||||
Diagnostic &Diags,
|
||||
const LangOptions &Features,
|
||||
const CompileOptions &CompileOpts,
|
||||
const std::string& InFile,
|
||||
const std::string& OutFile,
|
||||
bool GenerateDebugInfo);
|
||||
|
||||
ASTConsumer* CreateHTMLPrinter(const std::string &OutFile, Diagnostic &D,
|
||||
Preprocessor *PP, PreprocessorFactory* PPF);
|
||||
|
||||
ASTConsumer *CreateSerializationTest(Diagnostic &Diags,
|
||||
FileManager& FMgr);
|
||||
|
||||
ASTConsumer *CreateASTSerializer(const std::string& InFile,
|
||||
const std::string& EmitDir,
|
||||
Diagnostic &Diags);
|
||||
|
||||
ASTConsumer *CreateBlockRewriter(const std::string& InFile,
|
||||
const std::string& OutFile,
|
||||
Diagnostic &Diags,
|
||||
const LangOptions &LangOpts);
|
||||
|
||||
ASTConsumer *CreateInheritanceViewer(const std::string& clsname);
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
#include "AnalysisConsumer.h"
|
||||
|
||||
#endif
|
||||
@@ -1,69 +0,0 @@
|
||||
//===-- Analyses.def - Metadata about Static Analyses -----------*- 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 set of static analyses used by AnalysisConsumer.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef ANALYSIS
|
||||
#define ANALYSIS(NAME, CMDFLAG, DESC, SCOPE)
|
||||
#endif
|
||||
|
||||
ANALYSIS(CFGDump, "cfg-dump",
|
||||
"Display Control-Flow Graphs", Code)
|
||||
|
||||
ANALYSIS(CFGView, "cfg-view",
|
||||
"View Control-Flow Graphs using GraphViz", Code)
|
||||
|
||||
ANALYSIS(DisplayLiveVariables, "dump-live-variables",
|
||||
"Print results of live variable analysis", Code)
|
||||
|
||||
ANALYSIS(WarnDeadStores, "warn-dead-stores",
|
||||
"Warn about stores to dead variables", Code)
|
||||
|
||||
ANALYSIS(WarnUninitVals, "warn-uninit-values",
|
||||
"Warn about uses of uninitialized variables", Code)
|
||||
|
||||
ANALYSIS(WarnObjCMethSigs, "warn-objc-methodsigs",
|
||||
"Warn about Objective-C method signatures with type incompatibilities",
|
||||
ObjCImplementation)
|
||||
|
||||
ANALYSIS(WarnObjCDealloc, "warn-objc-missing-dealloc",
|
||||
"Warn about Objective-C classes that lack a correct implementation of -dealloc",
|
||||
ObjCImplementation)
|
||||
|
||||
ANALYSIS(WarnObjCUnusedIvars, "warn-objc-unused-ivars",
|
||||
"Warn about private ivars that are never used", ObjCImplementation)
|
||||
|
||||
ANALYSIS(CheckerSimple, "checker-simple",
|
||||
"Perform simple path-sensitive checks.", Code)
|
||||
|
||||
ANALYSIS(CheckerCFRef, "checker-cfref",
|
||||
"Run the [Core] Foundation reference count checker", Code)
|
||||
|
||||
|
||||
#ifndef ANALYSIS_STORE
|
||||
#define ANALYSIS_STORE(NAME, CMDFLAG, DESC)
|
||||
#endif
|
||||
|
||||
ANALYSIS_STORE(BasicStore, "basic", "Use basic analyzer store")
|
||||
ANALYSIS_STORE(RegionStore, "region", "Use region-based analyzer store")
|
||||
|
||||
#ifndef ANALYSIS_DIAGNOSTICS
|
||||
#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN, AUTOCREATE)
|
||||
#endif
|
||||
|
||||
ANALYSIS_DIAGNOSTICS(HTML, "html", "Output analysis results using HTML", CreateHTMLDiagnosticClient, false)
|
||||
ANALYSIS_DIAGNOSTICS(PLIST, "plist", "Output analysis results using Plists", CreatePlistDiagnosticClient, true)
|
||||
|
||||
#undef ANALYSIS
|
||||
#undef ANALYSIS_STORE
|
||||
#undef ANALYSIS_DIAGNOSTICS
|
||||
|
||||
|
||||
@@ -1,674 +0,0 @@
|
||||
//===--- AnalysisConsumer.cpp - ASTConsumer for running Analyses ----------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// "Meta" ASTConsumer for running different source analyses.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "ASTConsumers.h"
|
||||
#include "clang/Driver/PathDiagnosticClients.h"
|
||||
#include "clang/Driver/ManagerRegistry.h"
|
||||
#include "clang/AST/ASTConsumer.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/DeclObjC.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
#include "clang/AST/CFG.h"
|
||||
#include "clang/Analysis/Analyses/LiveVariables.h"
|
||||
#include "clang/Analysis/PathDiagnostic.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "clang/Basic/FileManager.h"
|
||||
#include "clang/AST/ParentMap.h"
|
||||
#include "clang/AST/TranslationUnit.h"
|
||||
#include "clang/Analysis/PathSensitive/BugReporter.h"
|
||||
#include "clang/Analysis/Analyses/LiveVariables.h"
|
||||
#include "clang/Analysis/LocalCheckers.h"
|
||||
#include "clang/Analysis/PathSensitive/GRTransferFuncs.h"
|
||||
#include "clang/Analysis/PathSensitive/GRExprEngine.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/Streams.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/System/Path.h"
|
||||
#include "llvm/System/Program.h"
|
||||
#include <vector>
|
||||
|
||||
using namespace clang;
|
||||
|
||||
static ExplodedNodeImpl::Auditor* CreateUbiViz();
|
||||
|
||||
// Analyzer options.
|
||||
static llvm::cl::opt<bool>
|
||||
PurgeDead("analyzer-purge-dead",
|
||||
llvm::cl::init(true),
|
||||
llvm::cl::desc("Remove dead symbols, bindings, and constraints before"
|
||||
" processing a statement."));
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Basic type definitions.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace {
|
||||
class AnalysisManager;
|
||||
typedef void (*CodeAction)(AnalysisManager& Mgr);
|
||||
} // end anonymous namespace
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// AnalysisConsumer declaration.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace {
|
||||
|
||||
class VISIBILITY_HIDDEN AnalysisConsumer : public ASTConsumer {
|
||||
typedef std::vector<CodeAction> Actions;
|
||||
Actions FunctionActions;
|
||||
Actions ObjCMethodActions;
|
||||
Actions ObjCImplementationActions;
|
||||
Actions TranslationUnitActions;
|
||||
|
||||
public:
|
||||
const bool VisGraphviz;
|
||||
const bool VisUbigraph;
|
||||
const bool TrimGraph;
|
||||
const LangOptions& LOpts;
|
||||
Diagnostic &Diags;
|
||||
ASTContext* Ctx;
|
||||
Preprocessor* PP;
|
||||
PreprocessorFactory* PPF;
|
||||
const std::string HTMLDir;
|
||||
const std::string FName;
|
||||
llvm::OwningPtr<PathDiagnosticClient> PD;
|
||||
bool AnalyzeAll;
|
||||
AnalysisStores SM;
|
||||
AnalysisDiagClients DC;
|
||||
const bool DisplayProgress;
|
||||
|
||||
AnalysisConsumer(Diagnostic &diags, Preprocessor* pp,
|
||||
PreprocessorFactory* ppf,
|
||||
const LangOptions& lopts,
|
||||
const std::string& fname,
|
||||
const std::string& htmldir,
|
||||
AnalysisStores sm, AnalysisDiagClients dc,
|
||||
bool visgraphviz, bool visubi, bool trim, bool analyzeAll,
|
||||
bool displayProgress)
|
||||
: VisGraphviz(visgraphviz), VisUbigraph(visubi), TrimGraph(trim),
|
||||
LOpts(lopts), Diags(diags),
|
||||
Ctx(0), PP(pp), PPF(ppf),
|
||||
HTMLDir(htmldir),
|
||||
FName(fname),
|
||||
AnalyzeAll(analyzeAll), SM(sm), DC(dc),
|
||||
DisplayProgress(displayProgress) {}
|
||||
|
||||
void addCodeAction(CodeAction action) {
|
||||
FunctionActions.push_back(action);
|
||||
ObjCMethodActions.push_back(action);
|
||||
}
|
||||
|
||||
void addObjCImplementationAction(CodeAction action) {
|
||||
ObjCImplementationActions.push_back(action);
|
||||
}
|
||||
|
||||
void addTranslationUnitAction(CodeAction action) {
|
||||
TranslationUnitActions.push_back(action);
|
||||
}
|
||||
|
||||
virtual void Initialize(ASTContext &Context) {
|
||||
Ctx = &Context;
|
||||
}
|
||||
|
||||
virtual void HandleTopLevelDecl(Decl *D);
|
||||
virtual void HandleTranslationUnit(TranslationUnit &TU);
|
||||
|
||||
void HandleCode(Decl* D, Stmt* Body, Actions& actions);
|
||||
};
|
||||
|
||||
|
||||
class VISIBILITY_HIDDEN AnalysisManager : public BugReporterData {
|
||||
Decl* D; Stmt* Body;
|
||||
TranslationUnit* TU;
|
||||
|
||||
enum AnalysisScope { ScopeTU, ScopeDecl } AScope;
|
||||
|
||||
AnalysisConsumer& C;
|
||||
bool DisplayedFunction;
|
||||
|
||||
llvm::OwningPtr<CFG> cfg;
|
||||
llvm::OwningPtr<LiveVariables> liveness;
|
||||
llvm::OwningPtr<ParentMap> PM;
|
||||
|
||||
// Configurable components creators.
|
||||
StoreManagerCreator CreateStoreMgr;
|
||||
ConstraintManagerCreator CreateConstraintMgr;
|
||||
|
||||
public:
|
||||
AnalysisManager(AnalysisConsumer& c, Decl* d, Stmt* b, bool displayProgress)
|
||||
: D(d), Body(b), TU(0), AScope(ScopeDecl), C(c),
|
||||
DisplayedFunction(!displayProgress) {
|
||||
setManagerCreators();
|
||||
}
|
||||
|
||||
AnalysisManager(AnalysisConsumer& c, TranslationUnit* tu,
|
||||
bool displayProgress)
|
||||
: D(0), Body(0), TU(tu), AScope(ScopeTU), C(c),
|
||||
DisplayedFunction(!displayProgress) {
|
||||
setManagerCreators();
|
||||
}
|
||||
|
||||
Decl* getCodeDecl() const {
|
||||
assert (AScope == ScopeDecl);
|
||||
return D;
|
||||
}
|
||||
|
||||
Stmt* getBody() const {
|
||||
assert (AScope == ScopeDecl);
|
||||
return Body;
|
||||
}
|
||||
|
||||
TranslationUnit* getTranslationUnit() const {
|
||||
assert (AScope == ScopeTU);
|
||||
return TU;
|
||||
}
|
||||
|
||||
StoreManagerCreator getStoreManagerCreator() {
|
||||
return CreateStoreMgr;
|
||||
};
|
||||
|
||||
ConstraintManagerCreator getConstraintManagerCreator() {
|
||||
return CreateConstraintMgr;
|
||||
}
|
||||
|
||||
virtual CFG* getCFG() {
|
||||
if (!cfg) cfg.reset(CFG::buildCFG(getBody()));
|
||||
return cfg.get();
|
||||
}
|
||||
|
||||
virtual ParentMap& getParentMap() {
|
||||
if (!PM)
|
||||
PM.reset(new ParentMap(getBody()));
|
||||
return *PM.get();
|
||||
}
|
||||
|
||||
virtual ASTContext& getContext() {
|
||||
return *C.Ctx;
|
||||
}
|
||||
|
||||
virtual SourceManager& getSourceManager() {
|
||||
return getContext().getSourceManager();
|
||||
}
|
||||
|
||||
virtual Diagnostic& getDiagnostic() {
|
||||
return C.Diags;
|
||||
}
|
||||
|
||||
const LangOptions& getLangOptions() const {
|
||||
return C.LOpts;
|
||||
}
|
||||
|
||||
virtual PathDiagnosticClient* getPathDiagnosticClient() {
|
||||
if (C.PD.get() == 0 && !C.HTMLDir.empty()) {
|
||||
switch (C.DC) {
|
||||
default:
|
||||
#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN, AUTOCREATE)\
|
||||
case PD_##NAME: C.PD.reset(CREATEFN(C.HTMLDir, C.PP, C.PPF)); break;
|
||||
#include "Analyses.def"
|
||||
}
|
||||
}
|
||||
return C.PD.get();
|
||||
}
|
||||
|
||||
virtual LiveVariables* getLiveVariables() {
|
||||
if (!liveness) {
|
||||
CFG* c = getCFG();
|
||||
if (!c) return 0;
|
||||
|
||||
liveness.reset(new LiveVariables(getContext(), *c));
|
||||
liveness->runOnCFG(*c);
|
||||
liveness->runOnAllBlocks(*c, 0, true);
|
||||
}
|
||||
|
||||
return liveness.get();
|
||||
}
|
||||
|
||||
bool shouldVisualizeGraphviz() const {
|
||||
return C.VisGraphviz;
|
||||
}
|
||||
|
||||
bool shouldVisualizeUbigraph() const {
|
||||
return C.VisUbigraph;
|
||||
}
|
||||
|
||||
bool shouldVisualize() const {
|
||||
return C.VisGraphviz || C.VisUbigraph;
|
||||
}
|
||||
|
||||
bool shouldTrimGraph() const {
|
||||
return C.TrimGraph;
|
||||
}
|
||||
|
||||
void DisplayFunction() {
|
||||
|
||||
if (DisplayedFunction)
|
||||
return;
|
||||
|
||||
DisplayedFunction = true;
|
||||
|
||||
// FIXME: Is getCodeDecl() always a named decl?
|
||||
if (isa<FunctionDecl>(getCodeDecl()) ||
|
||||
isa<ObjCMethodDecl>(getCodeDecl())) {
|
||||
NamedDecl *ND = cast<NamedDecl>(getCodeDecl());
|
||||
SourceManager &SM = getContext().getSourceManager();
|
||||
llvm::cerr << "ANALYZE: "
|
||||
<< SM.getPresumedLoc(ND->getLocation()).getFilename()
|
||||
<< ' ' << ND->getNameAsString() << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
/// Set configurable analyzer components creators. First check if there are
|
||||
/// components registered at runtime. Otherwise fall back to builtin
|
||||
/// components.
|
||||
void setManagerCreators() {
|
||||
if (ManagerRegistry::StoreMgrCreator != 0) {
|
||||
CreateStoreMgr = ManagerRegistry::StoreMgrCreator;
|
||||
}
|
||||
else {
|
||||
switch (C.SM) {
|
||||
default:
|
||||
assert(0 && "Unknown store manager.");
|
||||
#define ANALYSIS_STORE(NAME, CMDFLAG, DESC) \
|
||||
case NAME##Model: CreateStoreMgr = Create##NAME##Manager; break;
|
||||
#include "Analyses.def"
|
||||
}
|
||||
}
|
||||
|
||||
if (ManagerRegistry::ConstraintMgrCreator != 0)
|
||||
CreateConstraintMgr = ManagerRegistry::ConstraintMgrCreator;
|
||||
else
|
||||
CreateConstraintMgr = CreateBasicConstraintManager;
|
||||
|
||||
// Some DiagnosticClients should be created all the time instead of
|
||||
// lazily. Create those now.
|
||||
switch (C.DC) {
|
||||
default: break;
|
||||
#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN, AUTOCREATE)\
|
||||
case PD_##NAME: if (AUTOCREATE) getPathDiagnosticClient(); break;
|
||||
#include "Analyses.def"
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
namespace llvm {
|
||||
template <> struct FoldingSetTrait<CodeAction> {
|
||||
static inline void Profile(CodeAction X, FoldingSetNodeID& ID) {
|
||||
ID.AddPointer(reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(X)));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// AnalysisConsumer implementation.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void AnalysisConsumer::HandleTopLevelDecl(Decl *D) {
|
||||
switch (D->getKind()) {
|
||||
case Decl::Function: {
|
||||
FunctionDecl* FD = cast<FunctionDecl>(D);
|
||||
|
||||
if (FName.size() > 0 && FName != FD->getIdentifier()->getName())
|
||||
break;
|
||||
|
||||
Stmt* Body = FD->getBody();
|
||||
if (Body) HandleCode(FD, Body, FunctionActions);
|
||||
break;
|
||||
}
|
||||
|
||||
case Decl::ObjCMethod: {
|
||||
ObjCMethodDecl* MD = cast<ObjCMethodDecl>(D);
|
||||
|
||||
if (FName.size() > 0 && FName != MD->getSelector().getAsString())
|
||||
return;
|
||||
|
||||
Stmt* Body = MD->getBody();
|
||||
if (Body) HandleCode(MD, Body, ObjCMethodActions);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void AnalysisConsumer::HandleTranslationUnit(TranslationUnit& TU) {
|
||||
|
||||
if(!TranslationUnitActions.empty()) {
|
||||
AnalysisManager mgr(*this, &TU, DisplayProgress);
|
||||
for (Actions::iterator I = TranslationUnitActions.begin(),
|
||||
E = TranslationUnitActions.end(); I != E; ++I)
|
||||
(*I)(mgr);
|
||||
}
|
||||
|
||||
if (ObjCImplementationActions.empty())
|
||||
return;
|
||||
|
||||
for (TranslationUnit::iterator I = TU.begin(), E = TU.end(); I!=E; ++I) {
|
||||
|
||||
if (ObjCImplementationDecl* ID = dyn_cast<ObjCImplementationDecl>(*I))
|
||||
HandleCode(ID, 0, ObjCImplementationActions);
|
||||
}
|
||||
}
|
||||
|
||||
void AnalysisConsumer::HandleCode(Decl* D, Stmt* Body, Actions& actions) {
|
||||
|
||||
// Don't run the actions if an error has occured with parsing the file.
|
||||
if (Diags.hasErrorOccurred())
|
||||
return;
|
||||
|
||||
// Don't run the actions on declarations in header files unless
|
||||
// otherwise specified.
|
||||
if (!AnalyzeAll && !Ctx->getSourceManager().isFromMainFile(D->getLocation()))
|
||||
return;
|
||||
|
||||
// Create an AnalysisManager that will manage the state for analyzing
|
||||
// this method/function.
|
||||
AnalysisManager mgr(*this, D, Body, DisplayProgress);
|
||||
|
||||
// Dispatch on the actions.
|
||||
for (Actions::iterator I = actions.begin(), E = actions.end(); I != E; ++I)
|
||||
(*I)(mgr);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Analyses
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
static void ActionWarnDeadStores(AnalysisManager& mgr) {
|
||||
if (LiveVariables* L = mgr.getLiveVariables()) {
|
||||
BugReporter BR(mgr);
|
||||
CheckDeadStores(*L, BR);
|
||||
}
|
||||
}
|
||||
|
||||
static void ActionWarnUninitVals(AnalysisManager& mgr) {
|
||||
if (CFG* c = mgr.getCFG())
|
||||
CheckUninitializedValues(*c, mgr.getContext(), mgr.getDiagnostic());
|
||||
}
|
||||
|
||||
|
||||
static void ActionGRExprEngine(AnalysisManager& mgr, GRTransferFuncs* tf,
|
||||
bool StandardWarnings = true) {
|
||||
|
||||
|
||||
llvm::OwningPtr<GRTransferFuncs> TF(tf);
|
||||
|
||||
// Display progress.
|
||||
mgr.DisplayFunction();
|
||||
|
||||
// Construct the analysis engine.
|
||||
LiveVariables* L = mgr.getLiveVariables();
|
||||
if (!L) return;
|
||||
|
||||
GRExprEngine Eng(*mgr.getCFG(), *mgr.getCodeDecl(), mgr.getContext(), *L,
|
||||
PurgeDead,
|
||||
mgr.getStoreManagerCreator(),
|
||||
mgr.getConstraintManagerCreator());
|
||||
|
||||
Eng.setTransferFunctions(tf);
|
||||
|
||||
if (StandardWarnings) {
|
||||
Eng.RegisterInternalChecks();
|
||||
RegisterAppleChecks(Eng);
|
||||
}
|
||||
|
||||
// Set the graph auditor.
|
||||
llvm::OwningPtr<ExplodedNodeImpl::Auditor> Auditor;
|
||||
if (mgr.shouldVisualizeUbigraph()) {
|
||||
Auditor.reset(CreateUbiViz());
|
||||
ExplodedNodeImpl::SetAuditor(Auditor.get());
|
||||
}
|
||||
|
||||
// Execute the worklist algorithm.
|
||||
Eng.ExecuteWorkList();
|
||||
|
||||
// Release the auditor (if any) so that it doesn't monitor the graph
|
||||
// created BugReporter.
|
||||
ExplodedNodeImpl::SetAuditor(0);
|
||||
|
||||
// Display warnings.
|
||||
Eng.EmitWarnings(mgr);
|
||||
|
||||
// Visualize the exploded graph.
|
||||
if (mgr.shouldVisualizeGraphviz())
|
||||
Eng.ViewGraph(mgr.shouldTrimGraph());
|
||||
}
|
||||
|
||||
static void ActionCheckerCFRefAux(AnalysisManager& mgr, bool GCEnabled,
|
||||
bool StandardWarnings) {
|
||||
|
||||
GRTransferFuncs* TF = MakeCFRefCountTF(mgr.getContext(),
|
||||
GCEnabled,
|
||||
mgr.getLangOptions());
|
||||
|
||||
ActionGRExprEngine(mgr, TF, StandardWarnings);
|
||||
}
|
||||
|
||||
static void ActionCheckerCFRef(AnalysisManager& mgr) {
|
||||
|
||||
switch (mgr.getLangOptions().getGCMode()) {
|
||||
default:
|
||||
assert (false && "Invalid GC mode.");
|
||||
case LangOptions::NonGC:
|
||||
ActionCheckerCFRefAux(mgr, false, true);
|
||||
break;
|
||||
|
||||
case LangOptions::GCOnly:
|
||||
ActionCheckerCFRefAux(mgr, true, true);
|
||||
break;
|
||||
|
||||
case LangOptions::HybridGC:
|
||||
ActionCheckerCFRefAux(mgr, false, true);
|
||||
ActionCheckerCFRefAux(mgr, true, false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void ActionCheckerSimple(AnalysisManager& mgr) {
|
||||
ActionGRExprEngine(mgr, MakeGRSimpleValsTF());
|
||||
}
|
||||
|
||||
static void ActionDisplayLiveVariables(AnalysisManager& mgr) {
|
||||
if (LiveVariables* L = mgr.getLiveVariables()) {
|
||||
mgr.DisplayFunction();
|
||||
L->dumpBlockLiveness(mgr.getSourceManager());
|
||||
}
|
||||
}
|
||||
|
||||
static void ActionCFGDump(AnalysisManager& mgr) {
|
||||
if (CFG* c = mgr.getCFG()) {
|
||||
mgr.DisplayFunction();
|
||||
c->dump();
|
||||
}
|
||||
}
|
||||
|
||||
static void ActionCFGView(AnalysisManager& mgr) {
|
||||
if (CFG* c = mgr.getCFG()) {
|
||||
mgr.DisplayFunction();
|
||||
c->viewCFG();
|
||||
}
|
||||
}
|
||||
|
||||
static void ActionWarnObjCDealloc(AnalysisManager& mgr) {
|
||||
if (mgr.getLangOptions().getGCMode() == LangOptions::GCOnly)
|
||||
return;
|
||||
|
||||
BugReporter BR(mgr);
|
||||
|
||||
CheckObjCDealloc(cast<ObjCImplementationDecl>(mgr.getCodeDecl()),
|
||||
mgr.getLangOptions(), BR);
|
||||
}
|
||||
|
||||
static void ActionWarnObjCUnusedIvars(AnalysisManager& mgr) {
|
||||
BugReporter BR(mgr);
|
||||
CheckObjCUnusedIvar(cast<ObjCImplementationDecl>(mgr.getCodeDecl()), BR);
|
||||
}
|
||||
|
||||
static void ActionWarnObjCMethSigs(AnalysisManager& mgr) {
|
||||
BugReporter BR(mgr);
|
||||
|
||||
CheckObjCInstMethSignature(cast<ObjCImplementationDecl>(mgr.getCodeDecl()),
|
||||
BR);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// AnalysisConsumer creation.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
ASTConsumer* clang::CreateAnalysisConsumer(Analyses* Beg, Analyses* End,
|
||||
AnalysisStores SM,
|
||||
AnalysisDiagClients DC,
|
||||
Diagnostic &diags, Preprocessor* pp,
|
||||
PreprocessorFactory* ppf,
|
||||
const LangOptions& lopts,
|
||||
const std::string& fname,
|
||||
const std::string& htmldir,
|
||||
bool VisGraphviz, bool VisUbi,
|
||||
bool trim,
|
||||
bool analyzeAll,
|
||||
bool displayProgress) {
|
||||
|
||||
llvm::OwningPtr<AnalysisConsumer>
|
||||
C(new AnalysisConsumer(diags, pp, ppf, lopts, fname, htmldir, SM, DC,
|
||||
VisGraphviz, VisUbi, trim, analyzeAll,
|
||||
displayProgress));
|
||||
|
||||
for ( ; Beg != End ; ++Beg)
|
||||
switch (*Beg) {
|
||||
#define ANALYSIS(NAME, CMD, DESC, SCOPE)\
|
||||
case NAME:\
|
||||
C->add ## SCOPE ## Action(&Action ## NAME);\
|
||||
break;
|
||||
#include "Analyses.def"
|
||||
default: break;
|
||||
}
|
||||
|
||||
return C.take();
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Ubigraph Visualization. FIXME: Move to separate file.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace {
|
||||
|
||||
class UbigraphViz : public ExplodedNodeImpl::Auditor {
|
||||
llvm::OwningPtr<llvm::raw_ostream> Out;
|
||||
llvm::sys::Path Dir, Filename;
|
||||
unsigned Cntr;
|
||||
|
||||
typedef llvm::DenseMap<void*,unsigned> VMap;
|
||||
VMap M;
|
||||
|
||||
public:
|
||||
UbigraphViz(llvm::raw_ostream* out, llvm::sys::Path& dir,
|
||||
llvm::sys::Path& filename);
|
||||
|
||||
~UbigraphViz();
|
||||
|
||||
virtual void AddEdge(ExplodedNodeImpl* Src, ExplodedNodeImpl* Dst);
|
||||
};
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
static ExplodedNodeImpl::Auditor* CreateUbiViz() {
|
||||
std::string ErrMsg;
|
||||
|
||||
llvm::sys::Path Dir = llvm::sys::Path::GetTemporaryDirectory(&ErrMsg);
|
||||
if (!ErrMsg.empty())
|
||||
return 0;
|
||||
|
||||
llvm::sys::Path Filename = Dir;
|
||||
Filename.appendComponent("llvm_ubi");
|
||||
Filename.makeUnique(true,&ErrMsg);
|
||||
|
||||
if (!ErrMsg.empty())
|
||||
return 0;
|
||||
|
||||
llvm::cerr << "Writing '" << Filename << "'.\n";
|
||||
|
||||
llvm::OwningPtr<llvm::raw_fd_ostream> Stream;
|
||||
std::string filename = Filename.toString();
|
||||
Stream.reset(new llvm::raw_fd_ostream(filename.c_str(), false, ErrMsg));
|
||||
|
||||
if (!ErrMsg.empty())
|
||||
return 0;
|
||||
|
||||
return new UbigraphViz(Stream.take(), Dir, Filename);
|
||||
}
|
||||
|
||||
void UbigraphViz::AddEdge(ExplodedNodeImpl* Src, ExplodedNodeImpl* Dst) {
|
||||
|
||||
assert (Src != Dst && "Self-edges are not allowed.");
|
||||
|
||||
// Lookup the Src. If it is a new node, it's a root.
|
||||
VMap::iterator SrcI= M.find(Src);
|
||||
unsigned SrcID;
|
||||
|
||||
if (SrcI == M.end()) {
|
||||
M[Src] = SrcID = Cntr++;
|
||||
*Out << "('vertex', " << SrcID << ", ('color','#00ff00'))\n";
|
||||
}
|
||||
else
|
||||
SrcID = SrcI->second;
|
||||
|
||||
// Lookup the Dst.
|
||||
VMap::iterator DstI= M.find(Dst);
|
||||
unsigned DstID;
|
||||
|
||||
if (DstI == M.end()) {
|
||||
M[Dst] = DstID = Cntr++;
|
||||
*Out << "('vertex', " << DstID << ")\n";
|
||||
}
|
||||
else {
|
||||
// We have hit DstID before. Change its style to reflect a cache hit.
|
||||
DstID = DstI->second;
|
||||
*Out << "('change_vertex_style', " << DstID << ", 1)\n";
|
||||
}
|
||||
|
||||
// Add the edge.
|
||||
*Out << "('edge', " << SrcID << ", " << DstID
|
||||
<< ", ('arrow','true'), ('oriented', 'true'))\n";
|
||||
}
|
||||
|
||||
UbigraphViz::UbigraphViz(llvm::raw_ostream* out, llvm::sys::Path& dir,
|
||||
llvm::sys::Path& filename)
|
||||
: Out(out), Dir(dir), Filename(filename), Cntr(0) {
|
||||
|
||||
*Out << "('vertex_style_attribute', 0, ('shape', 'icosahedron'))\n";
|
||||
*Out << "('vertex_style', 1, 0, ('shape', 'sphere'), ('color', '#ffcc66'),"
|
||||
" ('size', '1.5'))\n";
|
||||
}
|
||||
|
||||
UbigraphViz::~UbigraphViz() {
|
||||
Out.reset(0);
|
||||
llvm::cerr << "Running 'ubiviz' program... ";
|
||||
std::string ErrMsg;
|
||||
llvm::sys::Path Ubiviz = llvm::sys::Program::FindProgramByName("ubiviz");
|
||||
std::vector<const char*> args;
|
||||
args.push_back(Ubiviz.c_str());
|
||||
args.push_back(Filename.c_str());
|
||||
args.push_back(0);
|
||||
|
||||
if (llvm::sys::Program::ExecuteAndWait(Ubiviz, &args[0],0,0,0,0,&ErrMsg)) {
|
||||
llvm::cerr << "Error viewing graph: " << ErrMsg << "\n";
|
||||
}
|
||||
|
||||
// Delete the directory.
|
||||
Dir.eraseFromDisk(true);
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
//===--- AnalysisConsumer.cpp - ASTConsumer for running Analyses ----------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// "Meta" ASTConsumer for running different source analyses.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef DRIVER_ANALYSISCONSUMER_H
|
||||
#define DRIVER_ANALYSISCONSUMER_H
|
||||
|
||||
namespace clang {
|
||||
|
||||
enum Analyses {
|
||||
#define ANALYSIS(NAME, CMDFLAG, DESC, SCOPE) NAME,
|
||||
#include "Analyses.def"
|
||||
NumAnalyses
|
||||
};
|
||||
|
||||
enum AnalysisStores {
|
||||
#define ANALYSIS_STORE(NAME, CMDFLAG, DESC) NAME##Model,
|
||||
#include "Analyses.def"
|
||||
NumStores
|
||||
};
|
||||
|
||||
enum AnalysisDiagClients {
|
||||
#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATFN, AUTOCREAT) PD_##NAME,
|
||||
#include "Analyses.def"
|
||||
NUM_ANALYSIS_DIAG_CLIENTS
|
||||
};
|
||||
|
||||
ASTConsumer* CreateAnalysisConsumer(Analyses* Beg, Analyses* End,
|
||||
AnalysisStores SM, AnalysisDiagClients DC,
|
||||
Diagnostic &diags, Preprocessor* pp,
|
||||
PreprocessorFactory* ppf,
|
||||
const LangOptions& lopts,
|
||||
const std::string& fname,
|
||||
const std::string& htmldir,
|
||||
bool VisualizeGraphViz,
|
||||
bool VisualizeUbi,
|
||||
bool VizTrimGraph,
|
||||
bool AnalyzeAll,
|
||||
bool DisplayProgress);
|
||||
} // end clang namespace
|
||||
|
||||
#endif
|
||||
@@ -1,374 +0,0 @@
|
||||
//===--- Backend.cpp - Interface to LLVM backend technologies -------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "ASTConsumers.h"
|
||||
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/AST/ASTConsumer.h"
|
||||
#include "clang/AST/TranslationUnit.h"
|
||||
#include "clang/Basic/TargetInfo.h"
|
||||
#include "clang/CodeGen/ModuleBuilder.h"
|
||||
#include "clang/Driver/CompileOptions.h"
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/ModuleProvider.h"
|
||||
#include "llvm/PassManager.h"
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
#include "llvm/Assembly/PrintModulePass.h"
|
||||
#include "llvm/Analysis/CallGraph.h"
|
||||
#include "llvm/Analysis/Verifier.h"
|
||||
#include "llvm/Bitcode/ReaderWriter.h"
|
||||
#include "llvm/CodeGen/RegAllocRegistry.h"
|
||||
#include "llvm/CodeGen/SchedulerRegistry.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/System/Path.h"
|
||||
#include "llvm/System/Program.h"
|
||||
#include "llvm/Target/TargetData.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
#include "llvm/Target/TargetMachineRegistry.h"
|
||||
#include "llvm/Transforms/Scalar.h"
|
||||
#include "llvm/Transforms/IPO.h"
|
||||
|
||||
using namespace clang;
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
class VISIBILITY_HIDDEN BackendConsumer : public ASTConsumer {
|
||||
BackendAction Action;
|
||||
CompileOptions CompileOpts;
|
||||
const std::string &InputFile;
|
||||
std::string OutputFile;
|
||||
bool GenerateDebugInfo;
|
||||
|
||||
llvm::OwningPtr<CodeGenerator> Gen;
|
||||
|
||||
llvm::Module *TheModule;
|
||||
llvm::TargetData *TheTargetData;
|
||||
llvm::raw_ostream *AsmOutStream;
|
||||
|
||||
mutable llvm::ModuleProvider *ModuleProvider;
|
||||
mutable FunctionPassManager *CodeGenPasses;
|
||||
mutable PassManager *PerModulePasses;
|
||||
mutable FunctionPassManager *PerFunctionPasses;
|
||||
|
||||
FunctionPassManager *getCodeGenPasses() const;
|
||||
PassManager *getPerModulePasses() const;
|
||||
FunctionPassManager *getPerFunctionPasses() const;
|
||||
|
||||
void CreatePasses();
|
||||
|
||||
/// AddEmitPasses - Add passes necessary to emit assembly or LLVM
|
||||
/// IR.
|
||||
///
|
||||
/// \return True on success. On failure \arg Error will be set to
|
||||
/// a user readable error message.
|
||||
bool AddEmitPasses(std::string &Error);
|
||||
|
||||
void EmitAssembly();
|
||||
|
||||
public:
|
||||
BackendConsumer(BackendAction action, Diagnostic &Diags,
|
||||
const LangOptions &Features, const CompileOptions &compopts,
|
||||
const std::string& infile, const std::string& outfile,
|
||||
bool debug) :
|
||||
Action(action),
|
||||
CompileOpts(compopts),
|
||||
InputFile(infile),
|
||||
OutputFile(outfile),
|
||||
GenerateDebugInfo(debug),
|
||||
Gen(CreateLLVMCodeGen(Diags, Features, InputFile, GenerateDebugInfo)),
|
||||
TheModule(0), TheTargetData(0), AsmOutStream(0), ModuleProvider(0),
|
||||
CodeGenPasses(0), PerModulePasses(0), PerFunctionPasses(0) {}
|
||||
|
||||
~BackendConsumer() {
|
||||
delete AsmOutStream;
|
||||
delete TheTargetData;
|
||||
delete ModuleProvider;
|
||||
delete CodeGenPasses;
|
||||
delete PerModulePasses;
|
||||
delete PerFunctionPasses;
|
||||
}
|
||||
|
||||
virtual void InitializeTU(TranslationUnit& TU) {
|
||||
Gen->InitializeTU(TU);
|
||||
|
||||
TheModule = Gen->GetModule();
|
||||
ModuleProvider = new ExistingModuleProvider(TheModule);
|
||||
TheTargetData =
|
||||
new llvm::TargetData(TU.getContext().Target.getTargetDescription());
|
||||
}
|
||||
|
||||
virtual void HandleTopLevelDecl(Decl *D) {
|
||||
Gen->HandleTopLevelDecl(D);
|
||||
}
|
||||
|
||||
virtual void HandleTranslationUnit(TranslationUnit& TU) {
|
||||
Gen->HandleTranslationUnit(TU);
|
||||
|
||||
EmitAssembly();
|
||||
// Force a flush here in case we never get released.
|
||||
if (AsmOutStream)
|
||||
AsmOutStream->flush();
|
||||
}
|
||||
|
||||
virtual void HandleTagDeclDefinition(TagDecl *D) {
|
||||
Gen->HandleTagDeclDefinition(D);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
FunctionPassManager *BackendConsumer::getCodeGenPasses() const {
|
||||
if (!CodeGenPasses) {
|
||||
CodeGenPasses = new FunctionPassManager(ModuleProvider);
|
||||
CodeGenPasses->add(new TargetData(*TheTargetData));
|
||||
}
|
||||
|
||||
return CodeGenPasses;
|
||||
}
|
||||
|
||||
PassManager *BackendConsumer::getPerModulePasses() const {
|
||||
if (!PerModulePasses) {
|
||||
PerModulePasses = new PassManager();
|
||||
PerModulePasses->add(new TargetData(*TheTargetData));
|
||||
}
|
||||
|
||||
return PerModulePasses;
|
||||
}
|
||||
|
||||
FunctionPassManager *BackendConsumer::getPerFunctionPasses() const {
|
||||
if (!PerFunctionPasses) {
|
||||
PerFunctionPasses = new FunctionPassManager(ModuleProvider);
|
||||
PerFunctionPasses->add(new TargetData(*TheTargetData));
|
||||
}
|
||||
|
||||
return PerFunctionPasses;
|
||||
}
|
||||
|
||||
bool BackendConsumer::AddEmitPasses(std::string &Error) {
|
||||
if (OutputFile == "-" || (InputFile == "-" && OutputFile.empty())) {
|
||||
AsmOutStream = new raw_stdout_ostream();
|
||||
sys::Program::ChangeStdoutToBinary();
|
||||
} else {
|
||||
if (OutputFile.empty()) {
|
||||
llvm::sys::Path Path(InputFile);
|
||||
Path.eraseSuffix();
|
||||
if (Action == Backend_EmitBC) {
|
||||
Path.appendSuffix("bc");
|
||||
} else if (Action == Backend_EmitLL) {
|
||||
Path.appendSuffix("ll");
|
||||
} else {
|
||||
Path.appendSuffix("s");
|
||||
}
|
||||
OutputFile = Path.toString();
|
||||
}
|
||||
|
||||
AsmOutStream = new raw_fd_ostream(OutputFile.c_str(), true, Error);
|
||||
if (!Error.empty())
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Action == Backend_EmitBC) {
|
||||
getPerModulePasses()->add(createBitcodeWriterPass(*AsmOutStream));
|
||||
} else if (Action == Backend_EmitLL) {
|
||||
getPerModulePasses()->add(createPrintModulePass(AsmOutStream));
|
||||
} else {
|
||||
bool Fast = CompileOpts.OptimizationLevel == 0;
|
||||
|
||||
// Create the TargetMachine for generating code.
|
||||
const TargetMachineRegistry::entry *TME =
|
||||
TargetMachineRegistry::getClosestStaticTargetForModule(*TheModule, Error);
|
||||
if (!TME) {
|
||||
Error = std::string("Unable to get target machine: ") + Error;
|
||||
return false;
|
||||
}
|
||||
|
||||
// FIXME: Support features?
|
||||
std::string FeatureStr;
|
||||
TargetMachine *TM = TME->CtorFn(*TheModule, FeatureStr);
|
||||
|
||||
// Set register scheduler & allocation policy.
|
||||
RegisterScheduler::setDefault(createDefaultScheduler);
|
||||
RegisterRegAlloc::setDefault(Fast ? createLocalRegisterAllocator :
|
||||
createLinearScanRegisterAllocator);
|
||||
|
||||
// From llvm-gcc:
|
||||
// If there are passes we have to run on the entire module, we do codegen
|
||||
// as a separate "pass" after that happens.
|
||||
// FIXME: This is disabled right now until bugs can be worked out. Reenable
|
||||
// this for fast -O0 compiles!
|
||||
FunctionPassManager *PM = getCodeGenPasses();
|
||||
|
||||
// Normal mode, emit a .s file by running the code generator.
|
||||
// Note, this also adds codegenerator level optimization passes.
|
||||
switch (TM->addPassesToEmitFile(*PM, *AsmOutStream,
|
||||
TargetMachine::AssemblyFile, Fast)) {
|
||||
default:
|
||||
case FileModel::Error:
|
||||
Error = "Unable to interface with target machine!\n";
|
||||
return false;
|
||||
case FileModel::AsmFile:
|
||||
break;
|
||||
}
|
||||
|
||||
if (TM->addPassesToEmitFileFinish(*CodeGenPasses, 0, Fast)) {
|
||||
Error = "Unable to interface with target machine!\n";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void BackendConsumer::CreatePasses() {
|
||||
// In -O0 if checking is disabled, we don't even have per-function passes.
|
||||
if (CompileOpts.VerifyModule)
|
||||
getPerFunctionPasses()->add(createVerifierPass());
|
||||
|
||||
if (CompileOpts.OptimizationLevel > 0) {
|
||||
FunctionPassManager *PM = getPerFunctionPasses();
|
||||
PM->add(createCFGSimplificationPass());
|
||||
if (CompileOpts.OptimizationLevel == 1)
|
||||
PM->add(createPromoteMemoryToRegisterPass());
|
||||
else
|
||||
PM->add(createScalarReplAggregatesPass());
|
||||
PM->add(createInstructionCombiningPass());
|
||||
}
|
||||
|
||||
// For now we always create per module passes.
|
||||
PassManager *PM = getPerModulePasses();
|
||||
if (CompileOpts.OptimizationLevel > 0) {
|
||||
if (CompileOpts.UnitAtATime)
|
||||
PM->add(createRaiseAllocationsPass()); // call %malloc -> malloc inst
|
||||
PM->add(createCFGSimplificationPass()); // Clean up disgusting code
|
||||
PM->add(createPromoteMemoryToRegisterPass()); // Kill useless allocas
|
||||
if (CompileOpts.UnitAtATime) {
|
||||
PM->add(createGlobalOptimizerPass()); // Optimize out global vars
|
||||
PM->add(createGlobalDCEPass()); // Remove unused fns and globs
|
||||
PM->add(createIPConstantPropagationPass()); // IP Constant Propagation
|
||||
PM->add(createDeadArgEliminationPass()); // Dead argument elimination
|
||||
}
|
||||
PM->add(createInstructionCombiningPass()); // Clean up after IPCP & DAE
|
||||
PM->add(createCFGSimplificationPass()); // Clean up after IPCP & DAE
|
||||
if (CompileOpts.UnitAtATime) {
|
||||
PM->add(createPruneEHPass()); // Remove dead EH info
|
||||
PM->add(createFunctionAttrsPass()); // Set readonly/readnone attrs
|
||||
}
|
||||
if (CompileOpts.InlineFunctions)
|
||||
PM->add(createFunctionInliningPass()); // Inline small functions
|
||||
else
|
||||
PM->add(createAlwaysInlinerPass()); // Respect always_inline
|
||||
if (CompileOpts.OptimizationLevel > 2)
|
||||
PM->add(createArgumentPromotionPass()); // Scalarize uninlined fn args
|
||||
if (CompileOpts.SimplifyLibCalls)
|
||||
PM->add(createSimplifyLibCallsPass()); // Library Call Optimizations
|
||||
PM->add(createInstructionCombiningPass()); // Cleanup for scalarrepl.
|
||||
PM->add(createJumpThreadingPass()); // Thread jumps.
|
||||
PM->add(createCFGSimplificationPass()); // Merge & remove BBs
|
||||
PM->add(createScalarReplAggregatesPass()); // Break up aggregate allocas
|
||||
PM->add(createInstructionCombiningPass()); // Combine silly seq's
|
||||
PM->add(createCondPropagationPass()); // Propagate conditionals
|
||||
PM->add(createTailCallEliminationPass()); // Eliminate tail calls
|
||||
PM->add(createCFGSimplificationPass()); // Merge & remove BBs
|
||||
PM->add(createReassociatePass()); // Reassociate expressions
|
||||
PM->add(createLoopRotatePass()); // Rotate Loop
|
||||
PM->add(createLICMPass()); // Hoist loop invariants
|
||||
PM->add(createLoopUnswitchPass(CompileOpts.OptimizeSize ? true : false));
|
||||
// PM->add(createLoopIndexSplitPass()); // Split loop index
|
||||
PM->add(createInstructionCombiningPass());
|
||||
PM->add(createIndVarSimplifyPass()); // Canonicalize indvars
|
||||
PM->add(createLoopDeletionPass()); // Delete dead loops
|
||||
if (CompileOpts.UnrollLoops)
|
||||
PM->add(createLoopUnrollPass()); // Unroll small loops
|
||||
PM->add(createInstructionCombiningPass()); // Clean up after the unroller
|
||||
PM->add(createGVNPass()); // Remove redundancies
|
||||
PM->add(createMemCpyOptPass()); // Remove memcpy / form memset
|
||||
PM->add(createSCCPPass()); // Constant prop with SCCP
|
||||
|
||||
// Run instcombine after redundancy elimination to exploit opportunities
|
||||
// opened up by them.
|
||||
PM->add(createInstructionCombiningPass());
|
||||
PM->add(createCondPropagationPass()); // Propagate conditionals
|
||||
PM->add(createDeadStoreEliminationPass()); // Delete dead stores
|
||||
PM->add(createAggressiveDCEPass()); // Delete dead instructions
|
||||
PM->add(createCFGSimplificationPass()); // Merge & remove BBs
|
||||
|
||||
if (CompileOpts.UnitAtATime) {
|
||||
PM->add(createStripDeadPrototypesPass()); // Get rid of dead prototypes
|
||||
PM->add(createDeadTypeEliminationPass()); // Eliminate dead types
|
||||
}
|
||||
|
||||
if (CompileOpts.OptimizationLevel > 1 && CompileOpts.UnitAtATime)
|
||||
PM->add(createConstantMergePass()); // Merge dup global constants
|
||||
} else {
|
||||
PM->add(createAlwaysInlinerPass());
|
||||
}
|
||||
}
|
||||
|
||||
/// EmitAssembly - Handle interaction with LLVM backend to generate
|
||||
/// actual machine code.
|
||||
void BackendConsumer::EmitAssembly() {
|
||||
// Silently ignore if we weren't initialized for some reason.
|
||||
if (!TheModule || !TheTargetData)
|
||||
return;
|
||||
|
||||
// Make sure IR generation is happy with the module. This is
|
||||
// released by the module provider.
|
||||
Module *M = Gen->ReleaseModule();
|
||||
if (!M) {
|
||||
// The module has been released by IR gen on failures, do not
|
||||
// double free.
|
||||
ModuleProvider->releaseModule();
|
||||
TheModule = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
assert(TheModule == M && "Unexpected module change during IR generation");
|
||||
|
||||
CreatePasses();
|
||||
|
||||
std::string Error;
|
||||
if (!AddEmitPasses(Error)) {
|
||||
// FIXME: Don't fail this way.
|
||||
llvm::cerr << "ERROR: " << Error << "\n";
|
||||
::exit(1);
|
||||
}
|
||||
|
||||
// Run passes. For now we do all passes at once, but eventually we
|
||||
// would like to have the option of streaming code generation.
|
||||
|
||||
if (PerFunctionPasses) {
|
||||
PerFunctionPasses->doInitialization();
|
||||
for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I)
|
||||
if (!I->isDeclaration())
|
||||
PerFunctionPasses->run(*I);
|
||||
PerFunctionPasses->doFinalization();
|
||||
}
|
||||
|
||||
if (PerModulePasses)
|
||||
PerModulePasses->run(*M);
|
||||
|
||||
if (CodeGenPasses) {
|
||||
CodeGenPasses->doInitialization();
|
||||
for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I)
|
||||
if (!I->isDeclaration())
|
||||
CodeGenPasses->run(*I);
|
||||
CodeGenPasses->doFinalization();
|
||||
}
|
||||
}
|
||||
|
||||
ASTConsumer *clang::CreateBackendConsumer(BackendAction Action,
|
||||
Diagnostic &Diags,
|
||||
const LangOptions &Features,
|
||||
const CompileOptions &CompileOpts,
|
||||
const std::string& InFile,
|
||||
const std::string& OutFile,
|
||||
bool GenerateDebugInfo) {
|
||||
return new BackendConsumer(Action, Diags, Features, CompileOpts,
|
||||
InFile, OutFile, GenerateDebugInfo);
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
set(LLVM_NO_RTTI 1)
|
||||
|
||||
set( LLVM_USED_LIBS
|
||||
clangCodeGen
|
||||
clangAnalysis
|
||||
clangRewrite
|
||||
clangSema
|
||||
clangDriver
|
||||
clangAST
|
||||
clangParse
|
||||
clangLex
|
||||
clangBasic
|
||||
)
|
||||
|
||||
set( LLVM_LINK_COMPONENTS
|
||||
${LLVM_TARGETS_TO_BUILD}
|
||||
bitreader
|
||||
bitwriter
|
||||
codegen
|
||||
ipo
|
||||
selectiondag
|
||||
)
|
||||
|
||||
add_clang_executable(clang
|
||||
AnalysisConsumer.cpp
|
||||
ASTConsumers.cpp
|
||||
Backend.cpp
|
||||
CacheTokens.cpp
|
||||
clang.cpp
|
||||
DependencyFile.cpp
|
||||
DiagChecker.cpp
|
||||
HTMLPrint.cpp
|
||||
PrintParserCallbacks.cpp
|
||||
PrintPreprocessedOutput.cpp
|
||||
RewriteBlocks.cpp
|
||||
RewriteMacros.cpp
|
||||
RewriteObjC.cpp
|
||||
RewriteTest.cpp
|
||||
SerializationTest.cpp
|
||||
)
|
||||
@@ -1,496 +0,0 @@
|
||||
//===--- CacheTokens.cpp - Caching of lexer tokens for PCH support --------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This provides a possible implementation of PCH support for Clang that is
|
||||
// based on caching lexed tokens and identifiers.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang.h"
|
||||
#include "clang/Basic/FileManager.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "clang/Basic/IdentifierTable.h"
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
#include "clang/Lex/Lexer.h"
|
||||
#include "clang/Lex/Preprocessor.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/System/Path.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/Streams.h"
|
||||
|
||||
using namespace clang;
|
||||
|
||||
typedef uint32_t Offset;
|
||||
|
||||
namespace {
|
||||
class VISIBILITY_HIDDEN PCHEntry {
|
||||
Offset TokenData, PPCondData;
|
||||
|
||||
public:
|
||||
PCHEntry() {}
|
||||
|
||||
PCHEntry(Offset td, Offset ppcd)
|
||||
: TokenData(td), PPCondData(ppcd) {}
|
||||
|
||||
Offset getTokenOffset() const { return TokenData; }
|
||||
Offset getPPCondTableOffset() const { return PPCondData; }
|
||||
};
|
||||
|
||||
class OffsetOpt {
|
||||
bool valid;
|
||||
Offset off;
|
||||
public:
|
||||
OffsetOpt() : valid(false) {}
|
||||
bool hasOffset() const { return valid; }
|
||||
Offset getOffset() const { assert(valid); return off; }
|
||||
void setOffset(Offset o) { off = o; valid = true; }
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
typedef llvm::DenseMap<const FileEntry*, PCHEntry> PCHMap;
|
||||
typedef llvm::DenseMap<const IdentifierInfo*,uint32_t> IDMap;
|
||||
typedef llvm::StringMap<OffsetOpt, llvm::BumpPtrAllocator> CachedStrsTy;
|
||||
|
||||
namespace {
|
||||
class VISIBILITY_HIDDEN PTHWriter {
|
||||
IDMap IM;
|
||||
llvm::raw_fd_ostream& Out;
|
||||
Preprocessor& PP;
|
||||
uint32_t idcount;
|
||||
PCHMap PM;
|
||||
CachedStrsTy CachedStrs;
|
||||
Offset CurStrOffset;
|
||||
std::vector<llvm::StringMapEntry<OffsetOpt>*> StrEntries;
|
||||
|
||||
//// Get the persistent id for the given IdentifierInfo*.
|
||||
uint32_t ResolveID(const IdentifierInfo* II);
|
||||
|
||||
/// Emit a token to the PTH file.
|
||||
void EmitToken(const Token& T);
|
||||
|
||||
void Emit8(uint32_t V) {
|
||||
Out << (unsigned char)(V);
|
||||
}
|
||||
|
||||
void Emit16(uint32_t V) {
|
||||
Out << (unsigned char)(V);
|
||||
Out << (unsigned char)(V >> 8);
|
||||
assert((V >> 16) == 0);
|
||||
}
|
||||
|
||||
void Emit24(uint32_t V) {
|
||||
Out << (unsigned char)(V);
|
||||
Out << (unsigned char)(V >> 8);
|
||||
Out << (unsigned char)(V >> 16);
|
||||
assert((V >> 24) == 0);
|
||||
}
|
||||
|
||||
void Emit32(uint32_t V) {
|
||||
Out << (unsigned char)(V);
|
||||
Out << (unsigned char)(V >> 8);
|
||||
Out << (unsigned char)(V >> 16);
|
||||
Out << (unsigned char)(V >> 24);
|
||||
}
|
||||
|
||||
void EmitBuf(const char* I, const char* E) {
|
||||
for ( ; I != E ; ++I) Out << *I;
|
||||
}
|
||||
|
||||
std::pair<Offset,std::pair<Offset, Offset> > EmitIdentifierTable();
|
||||
Offset EmitFileTable();
|
||||
PCHEntry LexTokens(Lexer& L);
|
||||
Offset EmitCachedSpellings();
|
||||
|
||||
public:
|
||||
PTHWriter(llvm::raw_fd_ostream& out, Preprocessor& pp)
|
||||
: Out(out), PP(pp), idcount(0), CurStrOffset(0) {}
|
||||
|
||||
void GeneratePTH();
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
uint32_t PTHWriter::ResolveID(const IdentifierInfo* II) {
|
||||
// Null IdentifierInfo's map to the persistent ID 0.
|
||||
if (!II)
|
||||
return 0;
|
||||
|
||||
IDMap::iterator I = IM.find(II);
|
||||
|
||||
if (I == IM.end()) {
|
||||
IM[II] = ++idcount; // Pre-increment since '0' is reserved for NULL.
|
||||
return idcount;
|
||||
}
|
||||
|
||||
return I->second; // We've already added 1.
|
||||
}
|
||||
|
||||
void PTHWriter::EmitToken(const Token& T) {
|
||||
Emit32(((uint32_t) T.getKind()) |
|
||||
(((uint32_t) T.getFlags()) << 8) |
|
||||
(((uint32_t) T.getLength()) << 16));
|
||||
|
||||
// Literals (strings, numbers, characters) get cached spellings.
|
||||
if (T.isLiteral()) {
|
||||
// FIXME: This uses the slow getSpelling(). Perhaps we do better
|
||||
// in the future? This only slows down PTH generation.
|
||||
const std::string &spelling = PP.getSpelling(T);
|
||||
const char* s = spelling.c_str();
|
||||
|
||||
// Get the string entry.
|
||||
llvm::StringMapEntry<OffsetOpt> *E =
|
||||
&CachedStrs.GetOrCreateValue(s, s+spelling.size());
|
||||
|
||||
if (!E->getValue().hasOffset()) {
|
||||
E->getValue().setOffset(CurStrOffset);
|
||||
StrEntries.push_back(E);
|
||||
CurStrOffset += spelling.size() + 1;
|
||||
}
|
||||
|
||||
Emit32(E->getValue().getOffset());
|
||||
}
|
||||
else
|
||||
Emit32(ResolveID(T.getIdentifierInfo()));
|
||||
|
||||
Emit32(PP.getSourceManager().getFileOffset(T.getLocation()));
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct VISIBILITY_HIDDEN IDData {
|
||||
const IdentifierInfo* II;
|
||||
uint32_t FileOffset;
|
||||
};
|
||||
|
||||
class VISIBILITY_HIDDEN CompareIDDataIndex {
|
||||
IDData* Table;
|
||||
public:
|
||||
CompareIDDataIndex(IDData* table) : Table(table) {}
|
||||
|
||||
bool operator()(unsigned i, unsigned j) const {
|
||||
const IdentifierInfo* II_i = Table[i].II;
|
||||
const IdentifierInfo* II_j = Table[j].II;
|
||||
|
||||
unsigned i_len = II_i->getLength();
|
||||
unsigned j_len = II_j->getLength();
|
||||
|
||||
if (i_len > j_len)
|
||||
return false;
|
||||
|
||||
if (i_len < j_len)
|
||||
return true;
|
||||
|
||||
// Otherwise, compare the strings themselves!
|
||||
return strncmp(II_i->getName(), II_j->getName(), i_len) < 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
std::pair<Offset,std::pair<Offset,Offset> >
|
||||
PTHWriter::EmitIdentifierTable() {
|
||||
llvm::BumpPtrAllocator Alloc;
|
||||
|
||||
// Build an inverse map from persistent IDs -> IdentifierInfo*.
|
||||
IDData* IIDMap = Alloc.Allocate<IDData>(idcount);
|
||||
|
||||
// Generate mapping from persistent IDs -> IdentifierInfo*.
|
||||
for (IDMap::iterator I=IM.begin(), E=IM.end(); I!=E; ++I) {
|
||||
// Decrement by 1 because we are using a vector for the lookup and
|
||||
// 0 is reserved for NULL.
|
||||
assert(I->second > 0);
|
||||
assert(I->second-1 < idcount);
|
||||
unsigned idx = I->second-1;
|
||||
IIDMap[idx].II = I->first;
|
||||
}
|
||||
|
||||
// We want to write out the strings in lexical order to support binary
|
||||
// search of strings to identifiers. Create such a table.
|
||||
unsigned *LexicalOrder = Alloc.Allocate<unsigned>(idcount);
|
||||
for (unsigned i = 0; i < idcount ; ++i ) LexicalOrder[i] = i;
|
||||
std::sort(LexicalOrder, LexicalOrder+idcount, CompareIDDataIndex(IIDMap));
|
||||
|
||||
// Write out the lexically-sorted table of persistent ids.
|
||||
Offset LexicalOff = Out.tell();
|
||||
for (unsigned i = 0; i < idcount ; ++i) Emit32(LexicalOrder[i]);
|
||||
|
||||
// Write out the string data itself.
|
||||
Offset DataOff = Out.tell();
|
||||
|
||||
for (unsigned i = 0; i < idcount; ++i) {
|
||||
IDData& d = IIDMap[i];
|
||||
d.FileOffset = Out.tell(); // Record the location for this data.
|
||||
unsigned len = d.II->getLength(); // Write out the string length.
|
||||
Emit32(len);
|
||||
const char* buf = d.II->getName(); // Write out the string data.
|
||||
EmitBuf(buf, buf+len);
|
||||
// Emit a null character for those clients expecting that IdentifierInfo
|
||||
// strings are null terminated.
|
||||
Emit8('\0');
|
||||
}
|
||||
|
||||
// Now emit the table mapping from persistent IDs to PTH file offsets.
|
||||
Offset IDOff = Out.tell();
|
||||
Emit32(idcount); // Emit the number of identifiers.
|
||||
for (unsigned i = 0 ; i < idcount; ++i) Emit32(IIDMap[i].FileOffset);
|
||||
|
||||
return std::make_pair(DataOff, std::make_pair(IDOff, LexicalOff));
|
||||
}
|
||||
|
||||
Offset PTHWriter::EmitFileTable() {
|
||||
// Determine the offset where this table appears in the PTH file.
|
||||
Offset off = (Offset) Out.tell();
|
||||
|
||||
// Output the size of the table.
|
||||
Emit32(PM.size());
|
||||
|
||||
for (PCHMap::iterator I=PM.begin(), E=PM.end(); I!=E; ++I) {
|
||||
const FileEntry* FE = I->first;
|
||||
const char* Name = FE->getName();
|
||||
unsigned size = strlen(Name);
|
||||
Emit32(size);
|
||||
EmitBuf(Name, Name+size);
|
||||
Emit32(I->second.getTokenOffset());
|
||||
Emit32(I->second.getPPCondTableOffset());
|
||||
}
|
||||
|
||||
return off;
|
||||
}
|
||||
|
||||
PCHEntry PTHWriter::LexTokens(Lexer& L) {
|
||||
// Pad 0's so that we emit tokens to a 4-byte alignment.
|
||||
// This speed up reading them back in.
|
||||
Offset off = (Offset) Out.tell();
|
||||
for (unsigned Pad = off % 4 ; Pad != 0 ; --Pad, ++off) Emit8(0);
|
||||
|
||||
// Keep track of matching '#if' ... '#endif'.
|
||||
typedef std::vector<std::pair<Offset, unsigned> > PPCondTable;
|
||||
PPCondTable PPCond;
|
||||
std::vector<unsigned> PPStartCond;
|
||||
bool ParsingPreprocessorDirective = false;
|
||||
Token Tok;
|
||||
|
||||
do {
|
||||
L.LexFromRawLexer(Tok);
|
||||
|
||||
if ((Tok.isAtStartOfLine() || Tok.is(tok::eof)) &&
|
||||
ParsingPreprocessorDirective) {
|
||||
// Insert an eom token into the token cache. It has the same
|
||||
// position as the next token that is not on the same line as the
|
||||
// preprocessor directive. Observe that we continue processing
|
||||
// 'Tok' when we exit this branch.
|
||||
Token Tmp = Tok;
|
||||
Tmp.setKind(tok::eom);
|
||||
Tmp.clearFlag(Token::StartOfLine);
|
||||
Tmp.setIdentifierInfo(0);
|
||||
EmitToken(Tmp);
|
||||
ParsingPreprocessorDirective = false;
|
||||
}
|
||||
|
||||
if (Tok.is(tok::identifier)) {
|
||||
Tok.setIdentifierInfo(PP.LookUpIdentifierInfo(Tok));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Tok.is(tok::hash) && Tok.isAtStartOfLine()) {
|
||||
// Special processing for #include. Store the '#' token and lex
|
||||
// the next token.
|
||||
assert(!ParsingPreprocessorDirective);
|
||||
Offset HashOff = (Offset) Out.tell();
|
||||
EmitToken(Tok);
|
||||
|
||||
// Get the next token.
|
||||
L.LexFromRawLexer(Tok);
|
||||
|
||||
assert(!Tok.isAtStartOfLine());
|
||||
|
||||
// Did we see 'include'/'import'/'include_next'?
|
||||
if (!Tok.is(tok::identifier))
|
||||
continue;
|
||||
|
||||
IdentifierInfo* II = PP.LookUpIdentifierInfo(Tok);
|
||||
Tok.setIdentifierInfo(II);
|
||||
tok::PPKeywordKind K = II->getPPKeywordID();
|
||||
|
||||
assert(K != tok::pp_not_keyword);
|
||||
ParsingPreprocessorDirective = true;
|
||||
|
||||
switch (K) {
|
||||
default:
|
||||
break;
|
||||
case tok::pp_include:
|
||||
case tok::pp_import:
|
||||
case tok::pp_include_next: {
|
||||
// Save the 'include' token.
|
||||
EmitToken(Tok);
|
||||
// Lex the next token as an include string.
|
||||
L.setParsingPreprocessorDirective(true);
|
||||
L.LexIncludeFilename(Tok);
|
||||
L.setParsingPreprocessorDirective(false);
|
||||
assert(!Tok.isAtStartOfLine());
|
||||
if (Tok.is(tok::identifier))
|
||||
Tok.setIdentifierInfo(PP.LookUpIdentifierInfo(Tok));
|
||||
|
||||
break;
|
||||
}
|
||||
case tok::pp_if:
|
||||
case tok::pp_ifdef:
|
||||
case tok::pp_ifndef: {
|
||||
// Ad an entry for '#if' and friends. We initially set the target index
|
||||
// to 0. This will get backpatched when we hit #endif.
|
||||
PPStartCond.push_back(PPCond.size());
|
||||
PPCond.push_back(std::make_pair(HashOff, 0U));
|
||||
break;
|
||||
}
|
||||
case tok::pp_endif: {
|
||||
// Add an entry for '#endif'. We set the target table index to itself.
|
||||
// This will later be set to zero when emitting to the PTH file. We
|
||||
// use 0 for uninitialized indices because that is easier to debug.
|
||||
unsigned index = PPCond.size();
|
||||
// Backpatch the opening '#if' entry.
|
||||
assert(!PPStartCond.empty());
|
||||
assert(PPCond.size() > PPStartCond.back());
|
||||
assert(PPCond[PPStartCond.back()].second == 0);
|
||||
PPCond[PPStartCond.back()].second = index;
|
||||
PPStartCond.pop_back();
|
||||
// Add the new entry to PPCond.
|
||||
PPCond.push_back(std::make_pair(HashOff, index));
|
||||
break;
|
||||
}
|
||||
case tok::pp_elif:
|
||||
case tok::pp_else: {
|
||||
// Add an entry for #elif or #else.
|
||||
// This serves as both a closing and opening of a conditional block.
|
||||
// This means that its entry will get backpatched later.
|
||||
unsigned index = PPCond.size();
|
||||
// Backpatch the previous '#if' entry.
|
||||
assert(!PPStartCond.empty());
|
||||
assert(PPCond.size() > PPStartCond.back());
|
||||
assert(PPCond[PPStartCond.back()].second == 0);
|
||||
PPCond[PPStartCond.back()].second = index;
|
||||
PPStartCond.pop_back();
|
||||
// Now add '#elif' as a new block opening.
|
||||
PPCond.push_back(std::make_pair(HashOff, 0U));
|
||||
PPStartCond.push_back(index);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
while (EmitToken(Tok), Tok.isNot(tok::eof));
|
||||
|
||||
assert(PPStartCond.empty() && "Error: imblanced preprocessor conditionals.");
|
||||
|
||||
// Next write out PPCond.
|
||||
Offset PPCondOff = (Offset) Out.tell();
|
||||
|
||||
// Write out the size of PPCond so that clients can identifer empty tables.
|
||||
Emit32(PPCond.size());
|
||||
|
||||
for (unsigned i = 0, e = PPCond.size(); i!=e; ++i) {
|
||||
Emit32(PPCond[i].first - off);
|
||||
uint32_t x = PPCond[i].second;
|
||||
assert(x != 0 && "PPCond entry not backpatched.");
|
||||
// Emit zero for #endifs. This allows us to do checking when
|
||||
// we read the PTH file back in.
|
||||
Emit32(x == i ? 0 : x);
|
||||
}
|
||||
|
||||
return PCHEntry(off, PPCondOff);
|
||||
}
|
||||
|
||||
Offset PTHWriter::EmitCachedSpellings() {
|
||||
// Write each cached strings to the PTH file.
|
||||
Offset SpellingsOff = Out.tell();
|
||||
|
||||
for (std::vector<llvm::StringMapEntry<OffsetOpt>*>::iterator
|
||||
I = StrEntries.begin(), E = StrEntries.end(); I!=E; ++I) {
|
||||
|
||||
const char* data = (*I)->getKeyData();
|
||||
EmitBuf(data, data + (*I)->getKeyLength());
|
||||
Emit8('\0');
|
||||
}
|
||||
|
||||
return SpellingsOff;
|
||||
}
|
||||
|
||||
void PTHWriter::GeneratePTH() {
|
||||
// Generate the prologue.
|
||||
Out << "cfe-pth";
|
||||
Emit32(PTHManager::Version);
|
||||
Offset JumpOffset = Out.tell();
|
||||
Emit32(0);
|
||||
|
||||
// Iterate over all the files in SourceManager. Create a lexer
|
||||
// for each file and cache the tokens.
|
||||
SourceManager &SM = PP.getSourceManager();
|
||||
const LangOptions &LOpts = PP.getLangOptions();
|
||||
|
||||
for (SourceManager::fileinfo_iterator I = SM.fileinfo_begin(),
|
||||
E = SM.fileinfo_end(); I != E; ++I) {
|
||||
const SrcMgr::ContentCache &C = *I;
|
||||
const FileEntry *FE = C.Entry;
|
||||
|
||||
// FIXME: Handle files with non-absolute paths.
|
||||
llvm::sys::Path P(FE->getName());
|
||||
if (!P.isAbsolute())
|
||||
continue;
|
||||
|
||||
assert(!PM.count(FE) && "fileinfo's are not uniqued on FileEntry?");
|
||||
|
||||
const llvm::MemoryBuffer *B = C.getBuffer();
|
||||
if (!B) continue;
|
||||
|
||||
FileID FID = SM.createFileID(FE, SourceLocation(), SrcMgr::C_User);
|
||||
Lexer L(FID, SM, LOpts);
|
||||
PM[FE] = LexTokens(L);
|
||||
}
|
||||
|
||||
// Write out the identifier table.
|
||||
const std::pair<Offset, std::pair<Offset,Offset> >& IdTableOff
|
||||
= EmitIdentifierTable();
|
||||
|
||||
// Write out the cached strings table.
|
||||
Offset SpellingOff = EmitCachedSpellings();
|
||||
|
||||
// Write out the file table.
|
||||
Offset FileTableOff = EmitFileTable();
|
||||
|
||||
// Finally, write out the offset table at the end.
|
||||
Offset JumpTargetOffset = Out.tell();
|
||||
Emit32(IdTableOff.first);
|
||||
Emit32(IdTableOff.second.first);
|
||||
Emit32(IdTableOff.second.second);
|
||||
Emit32(FileTableOff);
|
||||
Emit32(SpellingOff);
|
||||
|
||||
// Now write the offset in the prologue.
|
||||
Out.seek(JumpOffset);
|
||||
Emit32(JumpTargetOffset);
|
||||
}
|
||||
|
||||
void clang::CacheTokens(Preprocessor& PP, const std::string& OutFile) {
|
||||
// Lex through the entire file. This will populate SourceManager with
|
||||
// all of the header information.
|
||||
Token Tok;
|
||||
PP.EnterMainSourceFile();
|
||||
do { PP.Lex(Tok); } while (Tok.isNot(tok::eof));
|
||||
|
||||
// Open up the PTH file.
|
||||
std::string ErrMsg;
|
||||
llvm::raw_fd_ostream Out(OutFile.c_str(), true, ErrMsg);
|
||||
|
||||
if (!ErrMsg.empty()) {
|
||||
llvm::errs() << "PTH error: " << ErrMsg << "\n";
|
||||
return;
|
||||
}
|
||||
|
||||
// Create the PTHWriter and generate the PTH file.
|
||||
PTHWriter PW(Out, PP);
|
||||
PW.GeneratePTH();
|
||||
}
|
||||
@@ -1,272 +0,0 @@
|
||||
//===--- DependencyFile.cpp - Generate dependency file --------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This code generates dependency files.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "clang/Basic/FileManager.h"
|
||||
#include "clang/Lex/Preprocessor.h"
|
||||
#include "clang/Lex/PPCallbacks.h"
|
||||
#include "clang/Lex/DirectoryLookup.h"
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "llvm/ADT/StringSet.h"
|
||||
#include "llvm/System/Path.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
|
||||
using namespace clang;
|
||||
|
||||
namespace {
|
||||
class VISIBILITY_HIDDEN DependencyFileCallback : public PPCallbacks {
|
||||
std::vector<std::string> Files;
|
||||
llvm::StringSet<> FilesSet;
|
||||
const Preprocessor *PP;
|
||||
std::ofstream OS;
|
||||
const std::string &InputFile;
|
||||
std::vector<std::string> Targets;
|
||||
|
||||
private:
|
||||
bool FileMatchesDepCriteria(const char *Filename,
|
||||
SrcMgr::CharacteristicKind FileType);
|
||||
void OutputDependencyFile();
|
||||
|
||||
public:
|
||||
DependencyFileCallback(const Preprocessor *PP,
|
||||
const std::string &InputFile,
|
||||
const std::string &DepFile,
|
||||
const std::vector<std::string> &Targets,
|
||||
const char *&ErrStr);
|
||||
~DependencyFileCallback();
|
||||
virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason,
|
||||
SrcMgr::CharacteristicKind FileType);
|
||||
};
|
||||
}
|
||||
|
||||
static const char *DependencyFileExt = "d";
|
||||
static const char *ObjectFileExt = "o";
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Dependency file options
|
||||
//===----------------------------------------------------------------------===//
|
||||
static llvm::cl::opt<bool>
|
||||
GenerateDependencyFile("MD",
|
||||
llvm::cl::desc("Generate dependency for main source file "
|
||||
"(system headers included)"));
|
||||
|
||||
static llvm::cl::opt<bool>
|
||||
GenerateDependencyFileNoSysHeaders("MMD",
|
||||
llvm::cl::desc("Generate dependency for main source file "
|
||||
"(no system headers)"));
|
||||
|
||||
static llvm::cl::opt<std::string>
|
||||
DependencyOutputFile("MF",
|
||||
llvm::cl::desc("Specify dependency output file"));
|
||||
|
||||
static llvm::cl::list<std::string>
|
||||
DependencyTargets("MT",
|
||||
llvm::cl::desc("Specify target for dependency"));
|
||||
|
||||
// FIXME: Implement feature
|
||||
static llvm::cl::opt<bool>
|
||||
PhonyDependencyTarget("MP",
|
||||
llvm::cl::desc("Create phony target for each dependency "
|
||||
"(other than main file)"));
|
||||
|
||||
bool clang::CreateDependencyFileGen(Preprocessor *PP,
|
||||
std::string &OutputFile,
|
||||
const std::string &InputFile,
|
||||
const char *&ErrStr) {
|
||||
assert(!InputFile.empty() && "No file given");
|
||||
|
||||
ErrStr = NULL;
|
||||
|
||||
if (!GenerateDependencyFile && !GenerateDependencyFileNoSysHeaders) {
|
||||
if (!DependencyOutputFile.empty() || !DependencyTargets.empty() ||
|
||||
PhonyDependencyTarget)
|
||||
ErrStr = "Error: to generate dependencies you must specify -MD or -MMD\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Handle conflicting options
|
||||
if (GenerateDependencyFileNoSysHeaders)
|
||||
GenerateDependencyFile = false;
|
||||
|
||||
// Determine name of dependency output filename
|
||||
llvm::sys::Path DepFile;
|
||||
if (!DependencyOutputFile.empty())
|
||||
DepFile = DependencyOutputFile;
|
||||
else if (!OutputFile.empty()) {
|
||||
DepFile = OutputFile;
|
||||
DepFile.eraseSuffix();
|
||||
DepFile.appendSuffix(DependencyFileExt);
|
||||
}
|
||||
else {
|
||||
DepFile = InputFile;
|
||||
DepFile.eraseSuffix();
|
||||
DepFile.appendSuffix(DependencyFileExt);
|
||||
}
|
||||
|
||||
std::vector<std::string> Targets(DependencyTargets);
|
||||
|
||||
// Infer target name if unspecified
|
||||
if (Targets.empty()) {
|
||||
if (!OutputFile.empty()) {
|
||||
llvm::sys::Path TargetPath(OutputFile);
|
||||
TargetPath.eraseSuffix();
|
||||
TargetPath.appendSuffix(ObjectFileExt);
|
||||
Targets.push_back(TargetPath.toString());
|
||||
} else {
|
||||
llvm::sys::Path TargetPath(InputFile);
|
||||
TargetPath.eraseSuffix();
|
||||
TargetPath.appendSuffix(ObjectFileExt);
|
||||
Targets.push_back(TargetPath.toString());
|
||||
}
|
||||
}
|
||||
|
||||
DependencyFileCallback *PPDep =
|
||||
new DependencyFileCallback(PP, InputFile, DepFile.toString(),
|
||||
Targets, ErrStr);
|
||||
if (ErrStr){
|
||||
delete PPDep;
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
PP->setPPCallbacks(PPDep);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// FileMatchesDepCriteria - Determine whether the given Filename should be
|
||||
/// considered as a dependency.
|
||||
bool DependencyFileCallback::FileMatchesDepCriteria(const char *Filename,
|
||||
SrcMgr::CharacteristicKind FileType) {
|
||||
if (strcmp(InputFile.c_str(), Filename) != 0 &&
|
||||
strcmp("<predefines>", Filename) != 0) {
|
||||
if (GenerateDependencyFileNoSysHeaders)
|
||||
return FileType == SrcMgr::C_User;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void DependencyFileCallback::FileChanged(SourceLocation Loc,
|
||||
FileChangeReason Reason,
|
||||
SrcMgr::CharacteristicKind FileType) {
|
||||
if (Reason != PPCallbacks::EnterFile)
|
||||
return;
|
||||
|
||||
// Depedency generation really does want to go all the way to the file entry
|
||||
// for a source location to find out what is depended on. We do not want
|
||||
// #line markers to affect dependency generation!
|
||||
SourceManager &SM = PP->getSourceManager();
|
||||
|
||||
const FileEntry *FE =
|
||||
SM.getFileEntryForID(SM.getFileID(SM.getInstantiationLoc(Loc)));
|
||||
if (FE == 0) return;
|
||||
|
||||
const char *Filename = FE->getName();
|
||||
if (!FileMatchesDepCriteria(Filename, FileType))
|
||||
return;
|
||||
|
||||
// Remove leading "./"
|
||||
if (Filename[0] == '.' && Filename[1] == '/')
|
||||
Filename = &Filename[2];
|
||||
|
||||
if (FilesSet.insert(Filename))
|
||||
Files.push_back(Filename);
|
||||
}
|
||||
|
||||
void DependencyFileCallback::OutputDependencyFile() {
|
||||
// Write out the dependency targets, trying to avoid overly long
|
||||
// lines when possible. We try our best to emit exactly the same
|
||||
// dependency file as GCC (4.2), assuming the included files are the
|
||||
// same.
|
||||
const unsigned MaxColumns = 75;
|
||||
unsigned Columns = 0;
|
||||
|
||||
for (std::vector<std::string>::iterator
|
||||
I = Targets.begin(), E = Targets.end(); I != E; ++I) {
|
||||
unsigned N = I->length();
|
||||
if (Columns == 0) {
|
||||
Columns += N;
|
||||
OS << *I;
|
||||
} else if (Columns + N + 2 > MaxColumns) {
|
||||
Columns = N + 2;
|
||||
OS << " \\\n " << *I;
|
||||
} else {
|
||||
Columns += N + 1;
|
||||
OS << " " << *I;
|
||||
}
|
||||
}
|
||||
|
||||
OS << ":";
|
||||
Columns += 1;
|
||||
|
||||
// Now add each dependency in the order it was seen, but avoiding
|
||||
// duplicates.
|
||||
for (std::vector<std::string>::iterator I = Files.begin(),
|
||||
E = Files.end(); I != E; ++I) {
|
||||
// Start a new line if this would exceed the column limit. Make
|
||||
// sure to leave space for a trailing " \" in case we need to
|
||||
// break the line on the next iteration.
|
||||
unsigned N = I->length();
|
||||
if (Columns + (N + 1) + 2 > MaxColumns) {
|
||||
OS << " \\\n ";
|
||||
Columns = 2;
|
||||
}
|
||||
OS << " " << *I;
|
||||
Columns += N + 1;
|
||||
}
|
||||
OS << "\n";
|
||||
|
||||
// Create phony targets if requested.
|
||||
if (PhonyDependencyTarget) {
|
||||
// Skip the first entry, this is always the input file itself.
|
||||
for (std::vector<std::string>::iterator I = Files.begin() + 1,
|
||||
E = Files.end(); I != E; ++I) {
|
||||
OS << "\n";
|
||||
OS << *I << ":\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DependencyFileCallback::DependencyFileCallback(const Preprocessor *PP,
|
||||
const std::string &InputFile,
|
||||
const std::string &DepFile,
|
||||
const std::vector<std::string>
|
||||
&Targets,
|
||||
const char *&ErrStr)
|
||||
: PP(PP), InputFile(InputFile), Targets(Targets) {
|
||||
|
||||
OS.open(DepFile.c_str());
|
||||
if (OS.fail())
|
||||
ErrStr = "Could not open dependency output file\n";
|
||||
else
|
||||
ErrStr = NULL;
|
||||
|
||||
Files.push_back(InputFile);
|
||||
}
|
||||
|
||||
DependencyFileCallback::~DependencyFileCallback() {
|
||||
if ((!GenerateDependencyFile && !GenerateDependencyFileNoSysHeaders) ||
|
||||
OS.fail())
|
||||
return;
|
||||
|
||||
OutputDependencyFile();
|
||||
OS.close();
|
||||
}
|
||||
|
||||
@@ -1,282 +0,0 @@
|
||||
//===--- DiagChecker.cpp - Diagnostic Checking Functions ------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Process the input files and check that the diagnostic messages are expected.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang.h"
|
||||
#include "ASTConsumers.h"
|
||||
#include "clang/Driver/TextDiagnosticBuffer.h"
|
||||
#include "clang/Sema/ParseAST.h"
|
||||
#include "clang/AST/ASTConsumer.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "clang/Lex/Preprocessor.h"
|
||||
using namespace clang;
|
||||
|
||||
typedef TextDiagnosticBuffer::DiagList DiagList;
|
||||
typedef TextDiagnosticBuffer::const_iterator const_diag_iterator;
|
||||
|
||||
static void EmitError(Preprocessor &PP, SourceLocation Pos, const char *String){
|
||||
unsigned ID = PP.getDiagnostics().getCustomDiagID(Diagnostic::Error, String);
|
||||
PP.Diag(Pos, ID);
|
||||
}
|
||||
|
||||
|
||||
// USING THE DIAGNOSTIC CHECKER:
|
||||
//
|
||||
// Indicating that a line expects an error or a warning is simple. Put a comment
|
||||
// on the line that has the diagnostic, use "expected-{error,warning}" to tag
|
||||
// if it's an expected error or warning, and place the expected text between {{
|
||||
// and }} markers. The full text doesn't have to be included, only enough to
|
||||
// ensure that the correct diagnostic was emitted.
|
||||
//
|
||||
// Here's an example:
|
||||
//
|
||||
// int A = B; // expected-error {{use of undeclared identifier 'B'}}
|
||||
//
|
||||
// You can place as many diagnostics on one line as you wish. To make the code
|
||||
// more readable, you can use slash-newline to separate out the diagnostics.
|
||||
|
||||
/// FindDiagnostics - Go through the comment and see if it indicates expected
|
||||
/// diagnostics. If so, then put them in a diagnostic list.
|
||||
///
|
||||
static void FindDiagnostics(const char *CommentStart, unsigned CommentLen,
|
||||
DiagList &ExpectedDiags,
|
||||
Preprocessor &PP, SourceLocation Pos,
|
||||
const char *ExpectedStr) {
|
||||
const char *CommentEnd = CommentStart+CommentLen;
|
||||
unsigned ExpectedStrLen = strlen(ExpectedStr);
|
||||
|
||||
// Find all expected-foo diagnostics in the string and add them to
|
||||
// ExpectedDiags.
|
||||
while (CommentStart != CommentEnd) {
|
||||
CommentStart = std::find(CommentStart, CommentEnd, 'e');
|
||||
if (unsigned(CommentEnd-CommentStart) < ExpectedStrLen) return;
|
||||
|
||||
// If this isn't expected-foo, ignore it.
|
||||
if (memcmp(CommentStart, ExpectedStr, ExpectedStrLen)) {
|
||||
++CommentStart;
|
||||
continue;
|
||||
}
|
||||
|
||||
CommentStart += ExpectedStrLen;
|
||||
|
||||
// Skip whitespace.
|
||||
while (CommentStart != CommentEnd &&
|
||||
isspace(CommentStart[0]))
|
||||
++CommentStart;
|
||||
|
||||
// We should have a {{ now.
|
||||
if (CommentEnd-CommentStart < 2 ||
|
||||
CommentStart[0] != '{' || CommentStart[1] != '{') {
|
||||
if (std::find(CommentStart, CommentEnd, '{') != CommentEnd)
|
||||
EmitError(PP, Pos, "bogus characters before '{{' in expected string");
|
||||
else
|
||||
EmitError(PP, Pos, "cannot find start ('{{') of expected string");
|
||||
return;
|
||||
}
|
||||
CommentStart += 2;
|
||||
|
||||
// Find the }}.
|
||||
const char *ExpectedEnd = CommentStart;
|
||||
while (1) {
|
||||
ExpectedEnd = std::find(ExpectedEnd, CommentEnd, '}');
|
||||
if (CommentEnd-ExpectedEnd < 2) {
|
||||
EmitError(PP, Pos, "cannot find end ('}}') of expected string");
|
||||
return;
|
||||
}
|
||||
|
||||
if (ExpectedEnd[1] == '}')
|
||||
break;
|
||||
|
||||
++ExpectedEnd; // Skip over singular }'s
|
||||
}
|
||||
|
||||
std::string Msg(CommentStart, ExpectedEnd);
|
||||
std::string::size_type FindPos;
|
||||
while ((FindPos = Msg.find("\\n")) != std::string::npos)
|
||||
Msg.replace(FindPos, 2, "\n");
|
||||
ExpectedDiags.push_back(std::make_pair(Pos, Msg));
|
||||
|
||||
CommentStart = ExpectedEnd;
|
||||
}
|
||||
}
|
||||
|
||||
/// FindExpectedDiags - Lex the main source file to find all of the
|
||||
// expected errors and warnings.
|
||||
static void FindExpectedDiags(Preprocessor &PP,
|
||||
DiagList &ExpectedErrors,
|
||||
DiagList &ExpectedWarnings,
|
||||
DiagList &ExpectedNotes) {
|
||||
// Create a raw lexer to pull all the comments out of the main file. We don't
|
||||
// want to look in #include'd headers for expected-error strings.
|
||||
FileID FID = PP.getSourceManager().getMainFileID();
|
||||
|
||||
// Create a lexer to lex all the tokens of the main file in raw mode.
|
||||
Lexer RawLex(FID, PP.getSourceManager(), PP.getLangOptions());
|
||||
|
||||
// Return comments as tokens, this is how we find expected diagnostics.
|
||||
RawLex.SetCommentRetentionState(true);
|
||||
|
||||
Token Tok;
|
||||
Tok.setKind(tok::comment);
|
||||
while (Tok.isNot(tok::eof)) {
|
||||
RawLex.Lex(Tok);
|
||||
if (!Tok.is(tok::comment)) continue;
|
||||
|
||||
std::string Comment = PP.getSpelling(Tok);
|
||||
if (Comment.empty()) continue;
|
||||
|
||||
|
||||
// Find all expected errors.
|
||||
FindDiagnostics(&Comment[0], Comment.size(), ExpectedErrors, PP,
|
||||
Tok.getLocation(), "expected-error");
|
||||
|
||||
// Find all expected warnings.
|
||||
FindDiagnostics(&Comment[0], Comment.size(), ExpectedWarnings, PP,
|
||||
Tok.getLocation(), "expected-warning");
|
||||
|
||||
// Find all expected notes.
|
||||
FindDiagnostics(&Comment[0], Comment.size(), ExpectedNotes, PP,
|
||||
Tok.getLocation(), "expected-note");
|
||||
};
|
||||
}
|
||||
|
||||
/// PrintProblem - This takes a diagnostic map of the delta between expected and
|
||||
/// seen diagnostics. If there's anything in it, then something unexpected
|
||||
/// happened. Print the map out in a nice format and return "true". If the map
|
||||
/// is empty and we're not going to print things, then return "false".
|
||||
///
|
||||
static bool PrintProblem(SourceManager &SourceMgr,
|
||||
const_diag_iterator diag_begin,
|
||||
const_diag_iterator diag_end,
|
||||
const char *Msg) {
|
||||
if (diag_begin == diag_end) return false;
|
||||
|
||||
fprintf(stderr, "%s\n", Msg);
|
||||
|
||||
for (const_diag_iterator I = diag_begin, E = diag_end; I != E; ++I)
|
||||
fprintf(stderr, " Line %d: %s\n",
|
||||
SourceMgr.getInstantiationLineNumber(I->first),
|
||||
I->second.c_str());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// CompareDiagLists - Compare two diangnostic lists and return the difference
|
||||
/// between them.
|
||||
///
|
||||
static bool CompareDiagLists(SourceManager &SourceMgr,
|
||||
const_diag_iterator d1_begin,
|
||||
const_diag_iterator d1_end,
|
||||
const_diag_iterator d2_begin,
|
||||
const_diag_iterator d2_end,
|
||||
const char *Msg) {
|
||||
DiagList DiffList;
|
||||
|
||||
for (const_diag_iterator I = d1_begin, E = d1_end; I != E; ++I) {
|
||||
unsigned LineNo1 = SourceMgr.getInstantiationLineNumber(I->first);
|
||||
const std::string &Diag1 = I->second;
|
||||
bool Found = false;
|
||||
|
||||
for (const_diag_iterator II = d2_begin, IE = d2_end; II != IE; ++II) {
|
||||
unsigned LineNo2 = SourceMgr.getInstantiationLineNumber(II->first);
|
||||
if (LineNo1 != LineNo2) continue;
|
||||
|
||||
const std::string &Diag2 = II->second;
|
||||
if (Diag2.find(Diag1) != std::string::npos ||
|
||||
Diag1.find(Diag2) != std::string::npos) {
|
||||
Found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!Found)
|
||||
DiffList.push_back(std::make_pair(I->first, Diag1));
|
||||
}
|
||||
|
||||
return PrintProblem(SourceMgr, DiffList.begin(), DiffList.end(), Msg);
|
||||
}
|
||||
|
||||
/// CheckResults - This compares the expected results to those that
|
||||
/// were actually reported. It emits any discrepencies. Return "true" if there
|
||||
/// were problems. Return "false" otherwise.
|
||||
///
|
||||
static bool CheckResults(Preprocessor &PP,
|
||||
const DiagList &ExpectedErrors,
|
||||
const DiagList &ExpectedWarnings,
|
||||
const DiagList &ExpectedNotes) {
|
||||
const DiagnosticClient *DiagClient = PP.getDiagnostics().getClient();
|
||||
assert(DiagClient != 0 &&
|
||||
"DiagChecker requires a valid TextDiagnosticBuffer");
|
||||
const TextDiagnosticBuffer &Diags =
|
||||
static_cast<const TextDiagnosticBuffer&>(*DiagClient);
|
||||
SourceManager &SourceMgr = PP.getSourceManager();
|
||||
|
||||
// We want to capture the delta between what was expected and what was
|
||||
// seen.
|
||||
//
|
||||
// Expected \ Seen - set expected but not seen
|
||||
// Seen \ Expected - set seen but not expected
|
||||
bool HadProblem = false;
|
||||
|
||||
// See if there were errors that were expected but not seen.
|
||||
HadProblem |= CompareDiagLists(SourceMgr,
|
||||
ExpectedErrors.begin(), ExpectedErrors.end(),
|
||||
Diags.err_begin(), Diags.err_end(),
|
||||
"Errors expected but not seen:");
|
||||
|
||||
// See if there were errors that were seen but not expected.
|
||||
HadProblem |= CompareDiagLists(SourceMgr,
|
||||
Diags.err_begin(), Diags.err_end(),
|
||||
ExpectedErrors.begin(), ExpectedErrors.end(),
|
||||
"Errors seen but not expected:");
|
||||
|
||||
// See if there were warnings that were expected but not seen.
|
||||
HadProblem |= CompareDiagLists(SourceMgr,
|
||||
ExpectedWarnings.begin(),
|
||||
ExpectedWarnings.end(),
|
||||
Diags.warn_begin(), Diags.warn_end(),
|
||||
"Warnings expected but not seen:");
|
||||
|
||||
// See if there were warnings that were seen but not expected.
|
||||
HadProblem |= CompareDiagLists(SourceMgr,
|
||||
Diags.warn_begin(), Diags.warn_end(),
|
||||
ExpectedWarnings.begin(),
|
||||
ExpectedWarnings.end(),
|
||||
"Warnings seen but not expected:");
|
||||
|
||||
// See if there were notes that were expected but not seen.
|
||||
HadProblem |= CompareDiagLists(SourceMgr,
|
||||
ExpectedNotes.begin(),
|
||||
ExpectedNotes.end(),
|
||||
Diags.note_begin(), Diags.note_end(),
|
||||
"Notes expected but not seen:");
|
||||
|
||||
// See if there were notes that were seen but not expected.
|
||||
HadProblem |= CompareDiagLists(SourceMgr,
|
||||
Diags.note_begin(), Diags.note_end(),
|
||||
ExpectedNotes.begin(),
|
||||
ExpectedNotes.end(),
|
||||
"Notes seen but not expected:");
|
||||
|
||||
return HadProblem;
|
||||
}
|
||||
|
||||
|
||||
/// CheckDiagnostics - Gather the expected diagnostics and check them.
|
||||
bool clang::CheckDiagnostics(Preprocessor &PP) {
|
||||
// Gather the set of expected diagnostics.
|
||||
DiagList ExpectedErrors, ExpectedWarnings, ExpectedNotes;
|
||||
FindExpectedDiags(PP, ExpectedErrors, ExpectedWarnings, ExpectedNotes);
|
||||
|
||||
// Check that the expected diagnostics occurred.
|
||||
return CheckResults(PP, ExpectedErrors, ExpectedWarnings, ExpectedNotes);
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
//===--- HTMLPrint.cpp - Source code -> HTML pretty-printing --------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Pretty-printing of source code to HTML.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "ASTConsumers.h"
|
||||
#include "clang/AST/ASTConsumer.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/Rewrite/Rewriter.h"
|
||||
#include "clang/Rewrite/HTMLRewrite.h"
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "clang/Basic/FileManager.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
|
||||
using namespace clang;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Functional HTML pretty-printing.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace {
|
||||
class HTMLPrinter : public ASTConsumer {
|
||||
Rewriter R;
|
||||
std::string OutFilename;
|
||||
Diagnostic &Diags;
|
||||
Preprocessor *PP;
|
||||
PreprocessorFactory *PPF;
|
||||
public:
|
||||
HTMLPrinter(const std::string &OutFile, Diagnostic &D, Preprocessor *pp,
|
||||
PreprocessorFactory* ppf)
|
||||
: OutFilename(OutFile), Diags(D), PP(pp), PPF(ppf) {}
|
||||
virtual ~HTMLPrinter();
|
||||
|
||||
void Initialize(ASTContext &context);
|
||||
};
|
||||
}
|
||||
|
||||
ASTConsumer* clang::CreateHTMLPrinter(const std::string &OutFile,
|
||||
Diagnostic &D, Preprocessor *PP,
|
||||
PreprocessorFactory* PPF) {
|
||||
|
||||
return new HTMLPrinter(OutFile, D, PP, PPF);
|
||||
}
|
||||
|
||||
void HTMLPrinter::Initialize(ASTContext &context) {
|
||||
R.setSourceMgr(context.getSourceManager());
|
||||
}
|
||||
|
||||
HTMLPrinter::~HTMLPrinter() {
|
||||
if (Diags.hasErrorOccurred())
|
||||
return;
|
||||
|
||||
// Format the file.
|
||||
FileID FID = R.getSourceMgr().getMainFileID();
|
||||
const FileEntry* Entry = R.getSourceMgr().getFileEntryForID(FID);
|
||||
|
||||
html::AddLineNumbers(R, FID);
|
||||
html::AddHeaderFooterInternalBuiltinCSS(R, FID, Entry->getName());
|
||||
|
||||
// If we have a preprocessor, relex the file and syntax highlight.
|
||||
// We might not have a preprocessor if we come from a deserialized AST file,
|
||||
// for example.
|
||||
|
||||
if (PP) html::SyntaxHighlight(R, FID, *PP);
|
||||
if (PPF) html::HighlightMacros(R, FID, *PP);
|
||||
html::EscapeText(R, FID, false, true);
|
||||
|
||||
// Open the output.
|
||||
FILE *OutputFILE;
|
||||
if (OutFilename.empty() || OutFilename == "-")
|
||||
OutputFILE = stdout;
|
||||
else {
|
||||
OutputFILE = fopen(OutFilename.c_str(), "w+");
|
||||
if (OutputFILE == 0) {
|
||||
fprintf(stderr, "Error opening output file '%s'.\n", OutFilename.c_str());
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Emit the HTML.
|
||||
const RewriteBuffer &RewriteBuf = R.getEditBuffer(FID);
|
||||
char *Buffer = (char*)malloc(RewriteBuf.size());
|
||||
std::copy(RewriteBuf.begin(), RewriteBuf.end(), Buffer);
|
||||
fwrite(Buffer, 1, RewriteBuf.size(), OutputFILE);
|
||||
free(Buffer);
|
||||
|
||||
if (OutputFILE != stdout) fclose(OutputFILE);
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
LEVEL = ../../..
|
||||
TOOLNAME = clang
|
||||
CPPFLAGS += -I$(PROJ_SRC_DIR)/../include
|
||||
CXXFLAGS = -fno-rtti
|
||||
|
||||
# Include this here so we can get the configuration of the targets
|
||||
# that have been configured for construction. We have to do this
|
||||
# early so we can set up LINK_COMPONENTS before including Makefile.rules
|
||||
include $(LEVEL)/Makefile.config
|
||||
|
||||
LINK_COMPONENTS := $(TARGETS_TO_BUILD) bitreader bitwriter codegen ipo selectiondag
|
||||
USEDLIBS = clangCodeGen.a clangAnalysis.a clangRewrite.a clangSema.a \
|
||||
clangDriver.a clangAST.a clangParse.a clangLex.a \
|
||||
clangBasic.a
|
||||
|
||||
include $(LLVM_SRC_ROOT)/Makefile.rules
|
||||
@@ -1,642 +0,0 @@
|
||||
//===--- PrintParserActions.cpp - Implement -parse-print-callbacks mode ---===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This code simply runs the preprocessor on the input file and prints out the
|
||||
// result. This is the traditional behavior of the -E option.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang.h"
|
||||
#include "clang/Parse/Action.h"
|
||||
#include "clang/Parse/DeclSpec.h"
|
||||
#include "llvm/Support/Streams.h"
|
||||
using namespace clang;
|
||||
|
||||
namespace {
|
||||
class ParserPrintActions : public MinimalAction {
|
||||
|
||||
public:
|
||||
ParserPrintActions(Preprocessor &PP) : MinimalAction(PP) {}
|
||||
|
||||
// Printing Functions which also must call MinimalAction
|
||||
|
||||
/// ActOnDeclarator - This callback is invoked when a declarator is parsed
|
||||
/// and 'Init' specifies the initializer if any. This is for things like:
|
||||
/// "int X = 4" or "typedef int foo".
|
||||
virtual DeclTy *ActOnDeclarator(Scope *S, Declarator &D,
|
||||
DeclTy *LastInGroup) {
|
||||
llvm::cout << __FUNCTION__ << " ";
|
||||
if (IdentifierInfo *II = D.getIdentifier()) {
|
||||
llvm::cout << "'" << II->getName() << "'";
|
||||
} else {
|
||||
llvm::cout << "<anon>";
|
||||
}
|
||||
llvm::cout << "\n";
|
||||
|
||||
// Pass up to EmptyActions so that the symbol table is maintained right.
|
||||
return MinimalAction::ActOnDeclarator(S, D, LastInGroup);
|
||||
}
|
||||
/// ActOnPopScope - This callback is called immediately before the specified
|
||||
/// scope is popped and deleted.
|
||||
virtual void ActOnPopScope(SourceLocation Loc, Scope *S) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return MinimalAction::ActOnPopScope(Loc, S);
|
||||
}
|
||||
|
||||
/// ActOnTranslationUnitScope - This callback is called once, immediately
|
||||
/// after creating the translation unit scope (in Parser::Initialize).
|
||||
virtual void ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
MinimalAction::ActOnTranslationUnitScope(Loc, S);
|
||||
}
|
||||
|
||||
|
||||
Action::DeclTy *ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
|
||||
IdentifierInfo *ClassName,
|
||||
SourceLocation ClassLoc,
|
||||
IdentifierInfo *SuperName,
|
||||
SourceLocation SuperLoc,
|
||||
DeclTy * const *ProtoRefs,
|
||||
unsigned NumProtocols,
|
||||
SourceLocation EndProtoLoc,
|
||||
AttributeList *AttrList) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return MinimalAction::ActOnStartClassInterface(AtInterfaceLoc,
|
||||
ClassName, ClassLoc,
|
||||
SuperName, SuperLoc,
|
||||
ProtoRefs, NumProtocols,
|
||||
EndProtoLoc, AttrList);
|
||||
}
|
||||
|
||||
/// ActOnForwardClassDeclaration -
|
||||
/// Scope will always be top level file scope.
|
||||
Action::DeclTy *ActOnForwardClassDeclaration(SourceLocation AtClassLoc,
|
||||
IdentifierInfo **IdentList,
|
||||
unsigned NumElts) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return MinimalAction::ActOnForwardClassDeclaration(AtClassLoc, IdentList,
|
||||
NumElts);
|
||||
}
|
||||
|
||||
// Pure Printing
|
||||
|
||||
/// ActOnParamDeclarator - This callback is invoked when a parameter
|
||||
/// declarator is parsed. This callback only occurs for functions
|
||||
/// with prototypes. S is the function prototype scope for the
|
||||
/// parameters (C++ [basic.scope.proto]).
|
||||
virtual DeclTy *ActOnParamDeclarator(Scope *S, Declarator &D) {
|
||||
llvm::cout << __FUNCTION__ << " ";
|
||||
if (IdentifierInfo *II = D.getIdentifier()) {
|
||||
llvm::cout << "'" << II->getName() << "'";
|
||||
} else {
|
||||
llvm::cout << "<anon>";
|
||||
}
|
||||
llvm::cout << "\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// AddInitializerToDecl - This action is called immediately after
|
||||
/// ParseDeclarator (when an initializer is present). The code is factored
|
||||
/// this way to make sure we are able to handle the following:
|
||||
/// void func() { int xx = xx; }
|
||||
/// This allows ActOnDeclarator to register "xx" prior to parsing the
|
||||
/// initializer. The declaration above should still result in a warning,
|
||||
/// since the reference to "xx" is uninitialized.
|
||||
virtual void AddInitializerToDecl(DeclTy *Dcl, ExprArg Init) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
}
|
||||
|
||||
/// FinalizeDeclaratorGroup - After a sequence of declarators are parsed, this
|
||||
/// gives the actions implementation a chance to process the group as a whole.
|
||||
virtual DeclTy *FinalizeDeclaratorGroup(Scope *S, DeclTy *Group) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// ActOnStartOfFunctionDef - This is called at the start of a function
|
||||
/// definition, instead of calling ActOnDeclarator. The Declarator includes
|
||||
/// information about formal arguments that are part of this function.
|
||||
virtual DeclTy *ActOnStartOfFunctionDef(Scope *FnBodyScope, Declarator &D) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// ActOnStartOfFunctionDef - This is called at the start of a function
|
||||
/// definition, after the FunctionDecl has already been created.
|
||||
virtual DeclTy *ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclTy *D) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual void ObjCActOnStartOfMethodDef(Scope *FnBodyScope, DeclTy *D) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
}
|
||||
|
||||
/// ActOnFunctionDefBody - This is called when a function body has completed
|
||||
/// parsing. Decl is the DeclTy returned by ParseStartOfFunctionDef.
|
||||
virtual DeclTy *ActOnFinishFunctionBody(DeclTy *Decl, StmtArg Body) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual DeclTy *ActOnFileScopeAsmDecl(SourceLocation Loc, ExprArg AsmString) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with
|
||||
/// no declarator (e.g. "struct foo;") is parsed.
|
||||
virtual DeclTy *ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// ActOnLinkageSpec - Parsed a C++ linkage-specification that
|
||||
/// contained braces. Lang/StrSize contains the language string that
|
||||
/// was parsed at location Loc. Decls/NumDecls provides the
|
||||
/// declarations parsed inside the linkage specification.
|
||||
virtual DeclTy *ActOnLinkageSpec(SourceLocation Loc, SourceLocation LBrace,
|
||||
SourceLocation RBrace, const char *Lang,
|
||||
unsigned StrSize,
|
||||
DeclTy **Decls, unsigned NumDecls) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// ActOnLinkageSpec - Parsed a C++ linkage-specification without
|
||||
/// braces. Lang/StrSize contains the language string that was
|
||||
/// parsed at location Loc. D is the declaration parsed.
|
||||
virtual DeclTy *ActOnLinkageSpec(SourceLocation Loc, const char *Lang,
|
||||
unsigned StrSize, DeclTy *D) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Type Parsing Callbacks.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
virtual TypeResult ActOnTypeName(Scope *S, Declarator &D) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual DeclTy *ActOnTag(Scope *S, unsigned TagType, TagKind TK,
|
||||
SourceLocation KWLoc, const CXXScopeSpec &SS,
|
||||
IdentifierInfo *Name, SourceLocation NameLoc,
|
||||
AttributeList *Attr,
|
||||
MultiTemplateParamsArg TemplateParameterLists) {
|
||||
// TagType is an instance of DeclSpec::TST, indicating what kind of tag this
|
||||
// is (struct/union/enum/class).
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// Act on @defs() element found when parsing a structure. ClassName is the
|
||||
/// name of the referenced class.
|
||||
virtual void ActOnDefs(Scope *S, DeclTy *TagD, SourceLocation DeclStart,
|
||||
IdentifierInfo *ClassName,
|
||||
llvm::SmallVectorImpl<DeclTy*> &Decls) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
}
|
||||
|
||||
virtual DeclTy *ActOnField(Scope *S, DeclTy *TagD,
|
||||
SourceLocation DeclStart,
|
||||
Declarator &D, ExprTy *BitfieldWidth) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual DeclTy *ActOnIvar(Scope *S, SourceLocation DeclStart,
|
||||
Declarator &D, ExprTy *BitfieldWidth,
|
||||
tok::ObjCKeywordKind visibility) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual void ActOnFields(Scope* S, SourceLocation RecLoc, DeclTy *TagDecl,
|
||||
DeclTy **Fields, unsigned NumFields,
|
||||
SourceLocation LBrac, SourceLocation RBrac,
|
||||
AttributeList *AttrList) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
}
|
||||
|
||||
virtual DeclTy *ActOnEnumConstant(Scope *S, DeclTy *EnumDecl,
|
||||
DeclTy *LastEnumConstant,
|
||||
SourceLocation IdLoc, IdentifierInfo *Id,
|
||||
SourceLocation EqualLoc, ExprTy *Val) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual void ActOnEnumBody(SourceLocation EnumLoc, DeclTy *EnumDecl,
|
||||
DeclTy **Elements, unsigned NumElements) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
}
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Statement Parsing Callbacks.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
virtual OwningStmtResult ActOnNullStmt(SourceLocation SemiLoc) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return StmtEmpty();
|
||||
}
|
||||
|
||||
virtual OwningStmtResult ActOnCompoundStmt(SourceLocation L,
|
||||
SourceLocation R,
|
||||
MultiStmtArg Elts,
|
||||
bool isStmtExpr) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return StmtEmpty();
|
||||
}
|
||||
virtual OwningStmtResult ActOnDeclStmt(DeclTy *Decl,
|
||||
SourceLocation StartLoc,
|
||||
SourceLocation EndLoc) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return StmtEmpty();
|
||||
}
|
||||
|
||||
virtual OwningStmtResult ActOnExprStmt(ExprArg Expr) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return OwningStmtResult(*this, Expr.release());
|
||||
}
|
||||
|
||||
/// ActOnCaseStmt - Note that this handles the GNU 'case 1 ... 4' extension,
|
||||
/// which can specify an RHS value.
|
||||
virtual OwningStmtResult ActOnCaseStmt(SourceLocation CaseLoc,
|
||||
ExprArg LHSVal,
|
||||
SourceLocation DotDotDotLoc,
|
||||
ExprArg RHSVal,
|
||||
SourceLocation ColonLoc,
|
||||
StmtArg SubStmt) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return StmtEmpty();
|
||||
}
|
||||
virtual OwningStmtResult ActOnDefaultStmt(SourceLocation DefaultLoc,
|
||||
SourceLocation ColonLoc,
|
||||
StmtArg SubStmt, Scope *CurScope){
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return StmtEmpty();
|
||||
}
|
||||
|
||||
virtual OwningStmtResult ActOnLabelStmt(SourceLocation IdentLoc,
|
||||
IdentifierInfo *II,
|
||||
SourceLocation ColonLoc,
|
||||
StmtArg SubStmt) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return StmtEmpty();
|
||||
}
|
||||
|
||||
virtual OwningStmtResult ActOnIfStmt(SourceLocation IfLoc, ExprArg CondVal,
|
||||
StmtArg ThenVal,SourceLocation ElseLoc,
|
||||
StmtArg ElseVal) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return StmtEmpty();
|
||||
}
|
||||
|
||||
virtual OwningStmtResult ActOnStartOfSwitchStmt(ExprArg Cond) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return StmtEmpty();
|
||||
}
|
||||
|
||||
virtual OwningStmtResult ActOnFinishSwitchStmt(SourceLocation SwitchLoc,
|
||||
StmtArg Switch,
|
||||
StmtArg Body) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return StmtEmpty();
|
||||
}
|
||||
|
||||
virtual OwningStmtResult ActOnWhileStmt(SourceLocation WhileLoc,
|
||||
ExprArg Cond, StmtArg Body) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return StmtEmpty();
|
||||
}
|
||||
virtual OwningStmtResult ActOnDoStmt(SourceLocation DoLoc, StmtArg Body,
|
||||
SourceLocation WhileLoc, ExprArg Cond){
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return StmtEmpty();
|
||||
}
|
||||
virtual OwningStmtResult ActOnForStmt(SourceLocation ForLoc,
|
||||
SourceLocation LParenLoc,
|
||||
StmtArg First, ExprArg Second,
|
||||
ExprArg Third, SourceLocation RParenLoc,
|
||||
StmtArg Body) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return StmtEmpty();
|
||||
}
|
||||
virtual OwningStmtResult ActOnObjCForCollectionStmt(
|
||||
SourceLocation ForColLoc,
|
||||
SourceLocation LParenLoc,
|
||||
StmtArg First, ExprArg Second,
|
||||
SourceLocation RParenLoc, StmtArg Body) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return StmtEmpty();
|
||||
}
|
||||
virtual OwningStmtResult ActOnGotoStmt(SourceLocation GotoLoc,
|
||||
SourceLocation LabelLoc,
|
||||
IdentifierInfo *LabelII) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return StmtEmpty();
|
||||
}
|
||||
virtual OwningStmtResult ActOnIndirectGotoStmt(SourceLocation GotoLoc,
|
||||
SourceLocation StarLoc,
|
||||
ExprArg DestExp) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return StmtEmpty();
|
||||
}
|
||||
virtual OwningStmtResult ActOnContinueStmt(SourceLocation ContinueLoc,
|
||||
Scope *CurScope) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return StmtEmpty();
|
||||
}
|
||||
virtual OwningStmtResult ActOnBreakStmt(SourceLocation GotoLoc,
|
||||
Scope *CurScope) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return StmtEmpty();
|
||||
}
|
||||
virtual OwningStmtResult ActOnReturnStmt(SourceLocation ReturnLoc,
|
||||
ExprArg RetValExp) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return StmtEmpty();
|
||||
}
|
||||
virtual OwningStmtResult ActOnAsmStmt(SourceLocation AsmLoc,
|
||||
bool IsSimple,
|
||||
bool IsVolatile,
|
||||
unsigned NumOutputs,
|
||||
unsigned NumInputs,
|
||||
std::string *Names,
|
||||
MultiExprArg Constraints,
|
||||
MultiExprArg Exprs,
|
||||
ExprArg AsmString,
|
||||
MultiExprArg Clobbers,
|
||||
SourceLocation RParenLoc) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return StmtEmpty();
|
||||
}
|
||||
|
||||
// Objective-c statements
|
||||
virtual OwningStmtResult ActOnObjCAtCatchStmt(SourceLocation AtLoc,
|
||||
SourceLocation RParen,
|
||||
StmtArg Parm, StmtArg Body,
|
||||
StmtArg CatchList) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return StmtEmpty();
|
||||
}
|
||||
|
||||
virtual OwningStmtResult ActOnObjCAtFinallyStmt(SourceLocation AtLoc,
|
||||
StmtArg Body) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return StmtEmpty();
|
||||
}
|
||||
|
||||
virtual OwningStmtResult ActOnObjCAtTryStmt(SourceLocation AtLoc,
|
||||
StmtArg Try, StmtArg Catch,
|
||||
StmtArg Finally) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return StmtEmpty();
|
||||
}
|
||||
|
||||
virtual OwningStmtResult ActOnObjCAtThrowStmt(SourceLocation AtLoc,
|
||||
ExprArg Throw) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return StmtEmpty();
|
||||
}
|
||||
|
||||
virtual OwningStmtResult ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc,
|
||||
ExprArg SynchExpr,
|
||||
StmtArg SynchBody) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return StmtEmpty();
|
||||
}
|
||||
|
||||
// C++ Statements
|
||||
virtual DeclTy *ActOnExceptionDeclarator(Scope *S, Declarator &D) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual OwningStmtResult ActOnCXXCatchBlock(SourceLocation CatchLoc,
|
||||
DeclTy *ExceptionDecl,
|
||||
StmtArg HandlerBlock) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return StmtEmpty();
|
||||
}
|
||||
|
||||
virtual OwningStmtResult ActOnCXXTryBlock(SourceLocation TryLoc,
|
||||
StmtArg TryBlock,
|
||||
MultiStmtArg Handlers) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return StmtEmpty();
|
||||
}
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Expression Parsing Callbacks.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
// Primary Expressions.
|
||||
|
||||
/// ActOnIdentifierExpr - Parse an identifier in expression context.
|
||||
/// 'HasTrailingLParen' indicates whether or not the identifier has a '('
|
||||
/// token immediately after it.
|
||||
virtual OwningExprResult ActOnIdentifierExpr(Scope *S, SourceLocation Loc,
|
||||
IdentifierInfo &II,
|
||||
bool HasTrailingLParen,
|
||||
const CXXScopeSpec *SS) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return ExprEmpty();
|
||||
}
|
||||
|
||||
virtual OwningExprResult ActOnCXXOperatorFunctionIdExpr(
|
||||
Scope *S, SourceLocation OperatorLoc,
|
||||
OverloadedOperatorKind Op,
|
||||
bool HasTrailingLParen, const CXXScopeSpec &SS) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return ExprEmpty();
|
||||
}
|
||||
|
||||
virtual OwningExprResult ActOnCXXConversionFunctionExpr(
|
||||
Scope *S, SourceLocation OperatorLoc,
|
||||
TypeTy *Type, bool HasTrailingLParen,
|
||||
const CXXScopeSpec &SS) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return ExprEmpty();
|
||||
}
|
||||
|
||||
virtual OwningExprResult ActOnPredefinedExpr(SourceLocation Loc,
|
||||
tok::TokenKind Kind) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return ExprEmpty();
|
||||
}
|
||||
|
||||
virtual OwningExprResult ActOnCharacterConstant(const Token &) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return ExprEmpty();
|
||||
}
|
||||
|
||||
virtual OwningExprResult ActOnNumericConstant(const Token &) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return ExprEmpty();
|
||||
}
|
||||
|
||||
/// ActOnStringLiteral - The specified tokens were lexed as pasted string
|
||||
/// fragments (e.g. "foo" "bar" L"baz").
|
||||
virtual OwningExprResult ActOnStringLiteral(const Token *Toks,
|
||||
unsigned NumToks) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return ExprEmpty();
|
||||
}
|
||||
|
||||
virtual OwningExprResult ActOnParenExpr(SourceLocation L, SourceLocation R,
|
||||
ExprArg Val) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return move_res(Val); // Default impl returns operand.
|
||||
}
|
||||
|
||||
// Postfix Expressions.
|
||||
virtual OwningExprResult ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc,
|
||||
tok::TokenKind Kind,
|
||||
ExprArg Input) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return ExprEmpty();
|
||||
}
|
||||
virtual OwningExprResult ActOnArraySubscriptExpr(Scope *S, ExprArg Base,
|
||||
SourceLocation LLoc,
|
||||
ExprArg Idx,
|
||||
SourceLocation RLoc) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return ExprEmpty();
|
||||
}
|
||||
virtual OwningExprResult ActOnMemberReferenceExpr(Scope *S, ExprArg Base,
|
||||
SourceLocation OpLoc,
|
||||
tok::TokenKind OpKind,
|
||||
SourceLocation MemberLoc,
|
||||
IdentifierInfo &Member) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return ExprEmpty();
|
||||
}
|
||||
|
||||
virtual OwningExprResult ActOnCallExpr(Scope *S, ExprArg Fn,
|
||||
SourceLocation LParenLoc,
|
||||
MultiExprArg Args,
|
||||
SourceLocation *CommaLocs,
|
||||
SourceLocation RParenLoc) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return ExprEmpty();
|
||||
}
|
||||
|
||||
// Unary Operators. 'Tok' is the token for the operator.
|
||||
virtual OwningExprResult ActOnUnaryOp(Scope *S, SourceLocation OpLoc,
|
||||
tok::TokenKind Op, ExprArg Input) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return ExprEmpty();
|
||||
}
|
||||
virtual OwningExprResult
|
||||
ActOnSizeOfAlignOfExpr(SourceLocation OpLoc, bool isSizeof, bool isType,
|
||||
void *TyOrEx, const SourceRange &ArgRange) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return ExprEmpty();
|
||||
}
|
||||
|
||||
virtual OwningExprResult ActOnCompoundLiteral(SourceLocation LParen,
|
||||
TypeTy *Ty,
|
||||
SourceLocation RParen,
|
||||
ExprArg Op) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return ExprEmpty();
|
||||
}
|
||||
virtual OwningExprResult ActOnInitList(SourceLocation LParenLoc,
|
||||
MultiExprArg InitList,
|
||||
InitListDesignations &Designators,
|
||||
SourceLocation RParenLoc) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return ExprEmpty();
|
||||
}
|
||||
virtual OwningExprResult ActOnCastExpr(SourceLocation LParenLoc, TypeTy *Ty,
|
||||
SourceLocation RParenLoc,ExprArg Op){
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return ExprEmpty();
|
||||
}
|
||||
|
||||
virtual OwningExprResult ActOnBinOp(Scope *S, SourceLocation TokLoc,
|
||||
tok::TokenKind Kind,
|
||||
ExprArg LHS, ExprArg RHS) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return ExprEmpty();
|
||||
}
|
||||
|
||||
/// ActOnConditionalOp - Parse a ?: operation. Note that 'LHS' may be null
|
||||
/// in the case of a the GNU conditional expr extension.
|
||||
virtual OwningExprResult ActOnConditionalOp(SourceLocation QuestionLoc,
|
||||
SourceLocation ColonLoc,
|
||||
ExprArg Cond, ExprArg LHS,
|
||||
ExprArg RHS) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return ExprEmpty();
|
||||
}
|
||||
|
||||
//===--------------------- GNU Extension Expressions ------------------===//
|
||||
|
||||
virtual ExprResult ActOnAddrLabel(SourceLocation OpLoc, SourceLocation LabLoc,
|
||||
IdentifierInfo *LabelII) { // "&&foo"
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual ExprResult ActOnStmtExpr(SourceLocation LPLoc, StmtTy *SubStmt,
|
||||
SourceLocation RPLoc) { // "({..})"
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual ExprResult ActOnBuiltinOffsetOf(Scope *S, SourceLocation BuiltinLoc,
|
||||
SourceLocation TypeLoc, TypeTy *Arg1,
|
||||
OffsetOfComponent *CompPtr,
|
||||
unsigned NumComponents,
|
||||
SourceLocation RParenLoc) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
// __builtin_types_compatible_p(type1, type2)
|
||||
virtual ExprResult ActOnTypesCompatibleExpr(SourceLocation BuiltinLoc,
|
||||
TypeTy *arg1, TypeTy *arg2,
|
||||
SourceLocation RPLoc) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return 0;
|
||||
}
|
||||
// __builtin_choose_expr(constExpr, expr1, expr2)
|
||||
virtual ExprResult ActOnChooseExpr(SourceLocation BuiltinLoc,
|
||||
ExprTy *cond, ExprTy *expr1, ExprTy *expr2,
|
||||
SourceLocation RPLoc) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return 0;
|
||||
}
|
||||
// __builtin_overload(...)
|
||||
virtual ExprResult ActOnOverloadExpr(ExprTy **Args, unsigned NumArgs,
|
||||
SourceLocation *CommaLocs,
|
||||
SourceLocation BuiltinLoc,
|
||||
SourceLocation RPLoc) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// __builtin_va_arg(expr, type)
|
||||
virtual ExprResult ActOnVAArg(SourceLocation BuiltinLoc,
|
||||
ExprTy *expr, TypeTy *type,
|
||||
SourceLocation RPLoc) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
MinimalAction *clang::CreatePrintParserActionsAction(Preprocessor &PP) {
|
||||
return new ParserPrintActions(PP);
|
||||
}
|
||||
@@ -1,591 +0,0 @@
|
||||
//===--- PrintPreprocessedOutput.cpp - Implement the -E mode --------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This code simply runs the preprocessor on the input file and prints out the
|
||||
// result. This is the traditional behavior of the -E option.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang.h"
|
||||
#include "clang/Lex/PPCallbacks.h"
|
||||
#include "clang/Lex/Preprocessor.h"
|
||||
#include "clang/Lex/Pragma.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
#include "llvm/System/Path.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Config/config.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <cstdio>
|
||||
using namespace clang;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Preprocessed token printer
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
static llvm::cl::opt<bool>
|
||||
DisableLineMarkers("P", llvm::cl::desc("Disable linemarker output in -E mode"));
|
||||
static llvm::cl::opt<bool>
|
||||
EnableCommentOutput("C", llvm::cl::desc("Enable comment output in -E mode"));
|
||||
static llvm::cl::opt<bool>
|
||||
EnableMacroCommentOutput("CC",
|
||||
llvm::cl::desc("Enable comment output in -E mode, "
|
||||
"even from macro expansions"));
|
||||
|
||||
namespace {
|
||||
class PrintPPOutputPPCallbacks : public PPCallbacks {
|
||||
Preprocessor &PP;
|
||||
public:
|
||||
llvm::raw_ostream &OS;
|
||||
private:
|
||||
unsigned CurLine;
|
||||
bool EmittedTokensOnThisLine;
|
||||
SrcMgr::CharacteristicKind FileType;
|
||||
llvm::SmallString<512> CurFilename;
|
||||
bool Initialized;
|
||||
public:
|
||||
PrintPPOutputPPCallbacks(Preprocessor &pp, llvm::raw_ostream &os)
|
||||
: PP(pp), OS(os) {
|
||||
CurLine = 0;
|
||||
CurFilename += "<uninit>";
|
||||
EmittedTokensOnThisLine = false;
|
||||
FileType = SrcMgr::C_User;
|
||||
Initialized = false;
|
||||
}
|
||||
|
||||
void SetEmittedTokensOnThisLine() { EmittedTokensOnThisLine = true; }
|
||||
bool hasEmittedTokensOnThisLine() const { return EmittedTokensOnThisLine; }
|
||||
|
||||
virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason,
|
||||
SrcMgr::CharacteristicKind FileType);
|
||||
virtual void Ident(SourceLocation Loc, const std::string &str);
|
||||
virtual void PragmaComment(SourceLocation Loc, const IdentifierInfo *Kind,
|
||||
const std::string &Str);
|
||||
|
||||
|
||||
bool HandleFirstTokOnLine(Token &Tok);
|
||||
bool MoveToLine(SourceLocation Loc);
|
||||
bool AvoidConcat(const Token &PrevTok, const Token &Tok);
|
||||
void WriteLineInfo(unsigned LineNo, const char *Extra=0, unsigned ExtraLen=0);
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
void PrintPPOutputPPCallbacks::WriteLineInfo(unsigned LineNo,
|
||||
const char *Extra,
|
||||
unsigned ExtraLen) {
|
||||
if (EmittedTokensOnThisLine) {
|
||||
OS << '\n';
|
||||
EmittedTokensOnThisLine = false;
|
||||
}
|
||||
|
||||
OS << '#' << ' ' << LineNo << ' ' << '"';
|
||||
OS.write(&CurFilename[0], CurFilename.size());
|
||||
OS << '"';
|
||||
|
||||
if (ExtraLen)
|
||||
OS.write(Extra, ExtraLen);
|
||||
|
||||
if (FileType == SrcMgr::C_System)
|
||||
OS.write(" 3", 2);
|
||||
else if (FileType == SrcMgr::C_ExternCSystem)
|
||||
OS.write(" 3 4", 4);
|
||||
OS << '\n';
|
||||
}
|
||||
|
||||
/// MoveToLine - Move the output to the source line specified by the location
|
||||
/// object. We can do this by emitting some number of \n's, or be emitting a
|
||||
/// #line directive. This returns false if already at the specified line, true
|
||||
/// if some newlines were emitted.
|
||||
bool PrintPPOutputPPCallbacks::MoveToLine(SourceLocation Loc) {
|
||||
unsigned LineNo = PP.getSourceManager().getInstantiationLineNumber(Loc);
|
||||
|
||||
if (DisableLineMarkers) {
|
||||
if (LineNo == CurLine) return false;
|
||||
|
||||
CurLine = LineNo;
|
||||
|
||||
if (!EmittedTokensOnThisLine)
|
||||
return true;
|
||||
|
||||
OS << '\n';
|
||||
EmittedTokensOnThisLine = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// If this line is "close enough" to the original line, just print newlines,
|
||||
// otherwise print a #line directive.
|
||||
if (LineNo-CurLine <= 8) {
|
||||
if (LineNo-CurLine == 1)
|
||||
OS << '\n';
|
||||
else if (LineNo == CurLine)
|
||||
return false; // Spelling line moved, but instantiation line didn't.
|
||||
else {
|
||||
const char *NewLines = "\n\n\n\n\n\n\n\n";
|
||||
OS.write(NewLines, LineNo-CurLine);
|
||||
}
|
||||
} else {
|
||||
WriteLineInfo(LineNo, 0, 0);
|
||||
}
|
||||
|
||||
CurLine = LineNo;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/// FileChanged - Whenever the preprocessor enters or exits a #include file
|
||||
/// it invokes this handler. Update our conception of the current source
|
||||
/// position.
|
||||
void PrintPPOutputPPCallbacks::FileChanged(SourceLocation Loc,
|
||||
FileChangeReason Reason,
|
||||
SrcMgr::CharacteristicKind NewFileType) {
|
||||
// Unless we are exiting a #include, make sure to skip ahead to the line the
|
||||
// #include directive was at.
|
||||
SourceManager &SourceMgr = PP.getSourceManager();
|
||||
if (Reason == PPCallbacks::EnterFile) {
|
||||
SourceLocation IncludeLoc = SourceMgr.getPresumedLoc(Loc).getIncludeLoc();
|
||||
if (IncludeLoc.isValid())
|
||||
MoveToLine(IncludeLoc);
|
||||
} else if (Reason == PPCallbacks::SystemHeaderPragma) {
|
||||
MoveToLine(Loc);
|
||||
|
||||
// TODO GCC emits the # directive for this directive on the line AFTER the
|
||||
// directive and emits a bunch of spaces that aren't needed. Emulate this
|
||||
// strange behavior.
|
||||
}
|
||||
|
||||
Loc = SourceMgr.getInstantiationLoc(Loc);
|
||||
CurLine = SourceMgr.getLineNumber(Loc);
|
||||
|
||||
if (DisableLineMarkers) return;
|
||||
|
||||
CurFilename.clear();
|
||||
CurFilename += SourceMgr.getPresumedLoc(Loc).getFilename();
|
||||
Lexer::Stringify(CurFilename);
|
||||
FileType = NewFileType;
|
||||
|
||||
if (!Initialized) {
|
||||
WriteLineInfo(CurLine);
|
||||
Initialized = true;
|
||||
}
|
||||
|
||||
switch (Reason) {
|
||||
case PPCallbacks::EnterFile:
|
||||
WriteLineInfo(CurLine, " 1", 2);
|
||||
break;
|
||||
case PPCallbacks::ExitFile:
|
||||
WriteLineInfo(CurLine, " 2", 2);
|
||||
break;
|
||||
case PPCallbacks::SystemHeaderPragma:
|
||||
case PPCallbacks::RenameFile:
|
||||
WriteLineInfo(CurLine);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// Ident - Handle #ident directives when read by the preprocessor.
|
||||
///
|
||||
void PrintPPOutputPPCallbacks::Ident(SourceLocation Loc, const std::string &S) {
|
||||
MoveToLine(Loc);
|
||||
|
||||
OS.write("#ident ", strlen("#ident "));
|
||||
OS.write(&S[0], S.size());
|
||||
EmittedTokensOnThisLine = true;
|
||||
}
|
||||
|
||||
void PrintPPOutputPPCallbacks::PragmaComment(SourceLocation Loc,
|
||||
const IdentifierInfo *Kind,
|
||||
const std::string &Str) {
|
||||
MoveToLine(Loc);
|
||||
OS << "#pragma comment(" << Kind->getName();
|
||||
|
||||
if (!Str.empty()) {
|
||||
OS << ", \"";
|
||||
|
||||
for (unsigned i = 0, e = Str.size(); i != e; ++i) {
|
||||
unsigned char Char = Str[i];
|
||||
if (isprint(Char) && Char != '\\' && Char != '"')
|
||||
OS << (char)Char;
|
||||
else // Output anything hard as an octal escape.
|
||||
OS << '\\'
|
||||
<< (char)('0'+ ((Char >> 6) & 7))
|
||||
<< (char)('0'+ ((Char >> 3) & 7))
|
||||
<< (char)('0'+ ((Char >> 0) & 7));
|
||||
}
|
||||
OS << '"';
|
||||
}
|
||||
|
||||
OS << ')';
|
||||
EmittedTokensOnThisLine = true;
|
||||
}
|
||||
|
||||
|
||||
/// HandleFirstTokOnLine - When emitting a preprocessed file in -E mode, this
|
||||
/// is called for the first token on each new line. If this really is the start
|
||||
/// of a new logical line, handle it and return true, otherwise return false.
|
||||
/// This may not be the start of a logical line because the "start of line"
|
||||
/// marker is set for spelling lines, not instantiation ones.
|
||||
bool PrintPPOutputPPCallbacks::HandleFirstTokOnLine(Token &Tok) {
|
||||
// Figure out what line we went to and insert the appropriate number of
|
||||
// newline characters.
|
||||
if (!MoveToLine(Tok.getLocation()))
|
||||
return false;
|
||||
|
||||
// Print out space characters so that the first token on a line is
|
||||
// indented for easy reading.
|
||||
const SourceManager &SourceMgr = PP.getSourceManager();
|
||||
unsigned ColNo = SourceMgr.getInstantiationColumnNumber(Tok.getLocation());
|
||||
|
||||
// This hack prevents stuff like:
|
||||
// #define HASH #
|
||||
// HASH define foo bar
|
||||
// From having the # character end up at column 1, which makes it so it
|
||||
// is not handled as a #define next time through the preprocessor if in
|
||||
// -fpreprocessed mode.
|
||||
if (ColNo <= 1 && Tok.is(tok::hash))
|
||||
OS << ' ';
|
||||
|
||||
// Otherwise, indent the appropriate number of spaces.
|
||||
for (; ColNo > 1; --ColNo)
|
||||
OS << ' ';
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct UnknownPragmaHandler : public PragmaHandler {
|
||||
const char *Prefix;
|
||||
PrintPPOutputPPCallbacks *Callbacks;
|
||||
|
||||
UnknownPragmaHandler(const char *prefix, PrintPPOutputPPCallbacks *callbacks)
|
||||
: PragmaHandler(0), Prefix(prefix), Callbacks(callbacks) {}
|
||||
virtual void HandlePragma(Preprocessor &PP, Token &PragmaTok) {
|
||||
// Figure out what line we went to and insert the appropriate number of
|
||||
// newline characters.
|
||||
Callbacks->MoveToLine(PragmaTok.getLocation());
|
||||
Callbacks->OS.write(Prefix, strlen(Prefix));
|
||||
|
||||
// Read and print all of the pragma tokens.
|
||||
while (PragmaTok.isNot(tok::eom)) {
|
||||
if (PragmaTok.hasLeadingSpace())
|
||||
Callbacks->OS << ' ';
|
||||
std::string TokSpell = PP.getSpelling(PragmaTok);
|
||||
Callbacks->OS.write(&TokSpell[0], TokSpell.size());
|
||||
PP.LexUnexpandedToken(PragmaTok);
|
||||
}
|
||||
Callbacks->OS << '\n';
|
||||
}
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
|
||||
enum AvoidConcatInfo {
|
||||
/// By default, a token never needs to avoid concatenation. Most tokens (e.g.
|
||||
/// ',', ')', etc) don't cause a problem when concatenated.
|
||||
aci_never_avoid_concat = 0,
|
||||
|
||||
/// aci_custom_firstchar - AvoidConcat contains custom code to handle this
|
||||
/// token's requirements, and it needs to know the first character of the
|
||||
/// token.
|
||||
aci_custom_firstchar = 1,
|
||||
|
||||
/// aci_custom - AvoidConcat contains custom code to handle this token's
|
||||
/// requirements, but it doesn't need to know the first character of the
|
||||
/// token.
|
||||
aci_custom = 2,
|
||||
|
||||
/// aci_avoid_equal - Many tokens cannot be safely followed by an '='
|
||||
/// character. For example, "<<" turns into "<<=" when followed by an =.
|
||||
aci_avoid_equal = 4
|
||||
};
|
||||
|
||||
/// This array contains information for each token on what action to take when
|
||||
/// avoiding concatenation of tokens in the AvoidConcat method.
|
||||
static char TokenInfo[tok::NUM_TOKENS];
|
||||
|
||||
/// InitAvoidConcatTokenInfo - Tokens that must avoid concatenation should be
|
||||
/// marked by this function.
|
||||
static void InitAvoidConcatTokenInfo() {
|
||||
// These tokens have custom code in AvoidConcat.
|
||||
TokenInfo[tok::identifier ] |= aci_custom;
|
||||
TokenInfo[tok::numeric_constant] |= aci_custom_firstchar;
|
||||
TokenInfo[tok::period ] |= aci_custom_firstchar;
|
||||
TokenInfo[tok::amp ] |= aci_custom_firstchar;
|
||||
TokenInfo[tok::plus ] |= aci_custom_firstchar;
|
||||
TokenInfo[tok::minus ] |= aci_custom_firstchar;
|
||||
TokenInfo[tok::slash ] |= aci_custom_firstchar;
|
||||
TokenInfo[tok::less ] |= aci_custom_firstchar;
|
||||
TokenInfo[tok::greater ] |= aci_custom_firstchar;
|
||||
TokenInfo[tok::pipe ] |= aci_custom_firstchar;
|
||||
TokenInfo[tok::percent ] |= aci_custom_firstchar;
|
||||
TokenInfo[tok::colon ] |= aci_custom_firstchar;
|
||||
TokenInfo[tok::hash ] |= aci_custom_firstchar;
|
||||
TokenInfo[tok::arrow ] |= aci_custom_firstchar;
|
||||
|
||||
// These tokens change behavior if followed by an '='.
|
||||
TokenInfo[tok::amp ] |= aci_avoid_equal; // &=
|
||||
TokenInfo[tok::plus ] |= aci_avoid_equal; // +=
|
||||
TokenInfo[tok::minus ] |= aci_avoid_equal; // -=
|
||||
TokenInfo[tok::slash ] |= aci_avoid_equal; // /=
|
||||
TokenInfo[tok::less ] |= aci_avoid_equal; // <=
|
||||
TokenInfo[tok::greater ] |= aci_avoid_equal; // >=
|
||||
TokenInfo[tok::pipe ] |= aci_avoid_equal; // |=
|
||||
TokenInfo[tok::percent ] |= aci_avoid_equal; // %=
|
||||
TokenInfo[tok::star ] |= aci_avoid_equal; // *=
|
||||
TokenInfo[tok::exclaim ] |= aci_avoid_equal; // !=
|
||||
TokenInfo[tok::lessless ] |= aci_avoid_equal; // <<=
|
||||
TokenInfo[tok::greaterequal] |= aci_avoid_equal; // >>=
|
||||
TokenInfo[tok::caret ] |= aci_avoid_equal; // ^=
|
||||
TokenInfo[tok::equal ] |= aci_avoid_equal; // ==
|
||||
}
|
||||
|
||||
/// StartsWithL - Return true if the spelling of this token starts with 'L'.
|
||||
static bool StartsWithL(const Token &Tok, Preprocessor &PP) {
|
||||
if (!Tok.needsCleaning()) {
|
||||
SourceManager &SrcMgr = PP.getSourceManager();
|
||||
return *SrcMgr.getCharacterData(SrcMgr.getSpellingLoc(Tok.getLocation()))
|
||||
== 'L';
|
||||
}
|
||||
|
||||
if (Tok.getLength() < 256) {
|
||||
char Buffer[256];
|
||||
const char *TokPtr = Buffer;
|
||||
PP.getSpelling(Tok, TokPtr);
|
||||
return TokPtr[0] == 'L';
|
||||
}
|
||||
|
||||
return PP.getSpelling(Tok)[0] == 'L';
|
||||
}
|
||||
|
||||
/// IsIdentifierL - Return true if the spelling of this token is literally 'L'.
|
||||
static bool IsIdentifierL(const Token &Tok, Preprocessor &PP) {
|
||||
if (!Tok.needsCleaning()) {
|
||||
if (Tok.getLength() != 1)
|
||||
return false;
|
||||
SourceManager &SrcMgr = PP.getSourceManager();
|
||||
return *SrcMgr.getCharacterData(SrcMgr.getSpellingLoc(Tok.getLocation()))
|
||||
== 'L';
|
||||
}
|
||||
|
||||
if (Tok.getLength() < 256) {
|
||||
char Buffer[256];
|
||||
const char *TokPtr = Buffer;
|
||||
if (PP.getSpelling(Tok, TokPtr) != 1)
|
||||
return false;
|
||||
return TokPtr[0] == 'L';
|
||||
}
|
||||
|
||||
return PP.getSpelling(Tok) == "L";
|
||||
}
|
||||
|
||||
|
||||
/// AvoidConcat - If printing PrevTok immediately followed by Tok would cause
|
||||
/// the two individual tokens to be lexed as a single token, return true (which
|
||||
/// causes a space to be printed between them). This allows the output of -E
|
||||
/// mode to be lexed to the same token stream as lexing the input directly
|
||||
/// would.
|
||||
///
|
||||
/// This code must conservatively return true if it doesn't want to be 100%
|
||||
/// accurate. This will cause the output to include extra space characters, but
|
||||
/// the resulting output won't have incorrect concatenations going on. Examples
|
||||
/// include "..", which we print with a space between, because we don't want to
|
||||
/// track enough to tell "x.." from "...".
|
||||
bool PrintPPOutputPPCallbacks::AvoidConcat(const Token &PrevTok,
|
||||
const Token &Tok) {
|
||||
char Buffer[256];
|
||||
|
||||
tok::TokenKind PrevKind = PrevTok.getKind();
|
||||
if (PrevTok.getIdentifierInfo()) // Language keyword or named operator.
|
||||
PrevKind = tok::identifier;
|
||||
|
||||
// Look up information on when we should avoid concatenation with prevtok.
|
||||
unsigned ConcatInfo = TokenInfo[PrevKind];
|
||||
|
||||
// If prevtok never causes a problem for anything after it, return quickly.
|
||||
if (ConcatInfo == 0) return false;
|
||||
|
||||
if (ConcatInfo & aci_avoid_equal) {
|
||||
// If the next token is '=' or '==', avoid concatenation.
|
||||
if (Tok.is(tok::equal) || Tok.is(tok::equalequal))
|
||||
return true;
|
||||
ConcatInfo &= ~aci_avoid_equal;
|
||||
}
|
||||
|
||||
if (ConcatInfo == 0) return false;
|
||||
|
||||
|
||||
|
||||
// Basic algorithm: we look at the first character of the second token, and
|
||||
// determine whether it, if appended to the first token, would form (or would
|
||||
// contribute) to a larger token if concatenated.
|
||||
char FirstChar = 0;
|
||||
if (ConcatInfo & aci_custom) {
|
||||
// If the token does not need to know the first character, don't get it.
|
||||
} else if (IdentifierInfo *II = Tok.getIdentifierInfo()) {
|
||||
// Avoid spelling identifiers, the most common form of token.
|
||||
FirstChar = II->getName()[0];
|
||||
} else if (!Tok.needsCleaning()) {
|
||||
if (Tok.isLiteral() && Tok.getLiteralData()) {
|
||||
FirstChar = *Tok.getLiteralData();
|
||||
} else {
|
||||
SourceManager &SrcMgr = PP.getSourceManager();
|
||||
FirstChar =
|
||||
*SrcMgr.getCharacterData(SrcMgr.getSpellingLoc(Tok.getLocation()));
|
||||
}
|
||||
} else if (Tok.getLength() < 256) {
|
||||
const char *TokPtr = Buffer;
|
||||
PP.getSpelling(Tok, TokPtr);
|
||||
FirstChar = TokPtr[0];
|
||||
} else {
|
||||
FirstChar = PP.getSpelling(Tok)[0];
|
||||
}
|
||||
|
||||
switch (PrevKind) {
|
||||
default: assert(0 && "InitAvoidConcatTokenInfo built wrong");
|
||||
case tok::identifier: // id+id or id+number or id+L"foo".
|
||||
if (Tok.is(tok::numeric_constant) || Tok.getIdentifierInfo() ||
|
||||
Tok.is(tok::wide_string_literal) /* ||
|
||||
Tok.is(tok::wide_char_literal)*/)
|
||||
return true;
|
||||
|
||||
// If this isn't identifier + string, we're done.
|
||||
if (Tok.isNot(tok::char_constant) && Tok.isNot(tok::string_literal))
|
||||
return false;
|
||||
|
||||
// FIXME: need a wide_char_constant!
|
||||
|
||||
// If the string was a wide string L"foo" or wide char L'f', it would concat
|
||||
// with the previous identifier into fooL"bar". Avoid this.
|
||||
if (StartsWithL(Tok, PP))
|
||||
return true;
|
||||
|
||||
// Otherwise, this is a narrow character or string. If the *identifier* is
|
||||
// a literal 'L', avoid pasting L "foo" -> L"foo".
|
||||
return IsIdentifierL(PrevTok, PP);
|
||||
case tok::numeric_constant:
|
||||
return isalnum(FirstChar) || Tok.is(tok::numeric_constant) ||
|
||||
FirstChar == '+' || FirstChar == '-' || FirstChar == '.';
|
||||
case tok::period: // ..., .*, .1234
|
||||
return FirstChar == '.' || isdigit(FirstChar) ||
|
||||
(FirstChar == '*' && PP.getLangOptions().CPlusPlus);
|
||||
case tok::amp: // &&
|
||||
return FirstChar == '&';
|
||||
case tok::plus: // ++
|
||||
return FirstChar == '+';
|
||||
case tok::minus: // --, ->, ->*
|
||||
return FirstChar == '-' || FirstChar == '>';
|
||||
case tok::slash: //, /*, //
|
||||
return FirstChar == '*' || FirstChar == '/';
|
||||
case tok::less: // <<, <<=, <:, <%
|
||||
return FirstChar == '<' || FirstChar == ':' || FirstChar == '%';
|
||||
case tok::greater: // >>, >>=
|
||||
return FirstChar == '>';
|
||||
case tok::pipe: // ||
|
||||
return FirstChar == '|';
|
||||
case tok::percent: // %>, %:
|
||||
return (FirstChar == '>' || FirstChar == ':') &&
|
||||
PP.getLangOptions().Digraphs;
|
||||
case tok::colon: // ::, :>
|
||||
return (FirstChar == ':' && PP.getLangOptions().CPlusPlus) ||
|
||||
(FirstChar == '>' && PP.getLangOptions().Digraphs);
|
||||
case tok::hash: // ##, #@, %:%:
|
||||
return FirstChar == '#' || FirstChar == '@' || FirstChar == '%';
|
||||
case tok::arrow: // ->*
|
||||
return FirstChar == '*';
|
||||
}
|
||||
}
|
||||
|
||||
/// DoPrintPreprocessedInput - This implements -E mode.
|
||||
///
|
||||
void clang::DoPrintPreprocessedInput(Preprocessor &PP,
|
||||
const std::string &OutFile) {
|
||||
// Inform the preprocessor whether we want it to retain comments or not, due
|
||||
// to -C or -CC.
|
||||
PP.SetCommentRetentionState(EnableCommentOutput, EnableMacroCommentOutput);
|
||||
InitAvoidConcatTokenInfo();
|
||||
|
||||
|
||||
// Open the output buffer.
|
||||
std::string Err;
|
||||
llvm::raw_fd_ostream OS(OutFile.empty() ? "-" : OutFile.c_str(), false, Err);
|
||||
if (!Err.empty()) {
|
||||
fprintf(stderr, "%s\n", Err.c_str());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
OS.SetBufferSize(64*1024);
|
||||
|
||||
|
||||
Token Tok, PrevTok;
|
||||
char Buffer[256];
|
||||
PrintPPOutputPPCallbacks *Callbacks = new PrintPPOutputPPCallbacks(PP, OS);
|
||||
PP.setPPCallbacks(Callbacks);
|
||||
|
||||
PP.AddPragmaHandler(0, new UnknownPragmaHandler("#pragma", Callbacks));
|
||||
PP.AddPragmaHandler("GCC", new UnknownPragmaHandler("#pragma GCC",Callbacks));
|
||||
|
||||
// After we have configured the preprocessor, enter the main file.
|
||||
|
||||
// Start parsing the specified input file.
|
||||
PP.EnterMainSourceFile();
|
||||
|
||||
// Consume all of the tokens that come from the predefines buffer. Those
|
||||
// should not be emitted into the output and are guaranteed to be at the
|
||||
// start.
|
||||
const SourceManager &SourceMgr = PP.getSourceManager();
|
||||
do PP.Lex(Tok);
|
||||
while (Tok.isNot(tok::eof) && Tok.getLocation().isFileID() &&
|
||||
!strcmp(SourceMgr.getPresumedLoc(Tok.getLocation()).getFilename(),
|
||||
"<predefines>"));
|
||||
|
||||
while (1) {
|
||||
|
||||
// If this token is at the start of a line, emit newlines if needed.
|
||||
if (Tok.isAtStartOfLine() && Callbacks->HandleFirstTokOnLine(Tok)) {
|
||||
// done.
|
||||
} else if (Tok.hasLeadingSpace() ||
|
||||
// If we haven't emitted a token on this line yet, PrevTok isn't
|
||||
// useful to look at and no concatenation could happen anyway.
|
||||
(Callbacks->hasEmittedTokensOnThisLine() &&
|
||||
// Don't print "-" next to "-", it would form "--".
|
||||
Callbacks->AvoidConcat(PrevTok, Tok))) {
|
||||
OS << ' ';
|
||||
}
|
||||
|
||||
if (IdentifierInfo *II = Tok.getIdentifierInfo()) {
|
||||
OS.write(II->getName(), II->getLength());
|
||||
} else if (Tok.isLiteral() && !Tok.needsCleaning() &&
|
||||
Tok.getLiteralData()) {
|
||||
OS.write(Tok.getLiteralData(), Tok.getLength());
|
||||
} else if (Tok.getLength() < 256) {
|
||||
const char *TokPtr = Buffer;
|
||||
unsigned Len = PP.getSpelling(Tok, TokPtr);
|
||||
OS.write(TokPtr, Len);
|
||||
} else {
|
||||
std::string S = PP.getSpelling(Tok);
|
||||
OS.write(&S[0], S.size());
|
||||
}
|
||||
Callbacks->SetEmittedTokensOnThisLine();
|
||||
|
||||
if (Tok.is(tok::eof)) break;
|
||||
|
||||
PrevTok = Tok;
|
||||
PP.Lex(Tok);
|
||||
}
|
||||
OS << '\n';
|
||||
|
||||
// Flush the ostream.
|
||||
OS.flush();
|
||||
|
||||
// If an error occurred, remove the output file.
|
||||
if (PP.getDiagnostics().hasErrorOccurred() && !OutFile.empty())
|
||||
llvm::sys::Path(OutFile).eraseFromDisk();
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,236 +0,0 @@
|
||||
//===--- RewriteMacros.cpp - Rewrite macros into their expansions ---------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This code rewrites macro invocations into their expansions. This gives you
|
||||
// a macro expanded file that retains comments and #includes.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang.h"
|
||||
#include "clang/Rewrite/Rewriter.h"
|
||||
#include "clang/Lex/Preprocessor.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "llvm/Support/Streams.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/System/Path.h"
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
using namespace clang;
|
||||
|
||||
/// isSameToken - Return true if the two specified tokens start have the same
|
||||
/// content.
|
||||
static bool isSameToken(Token &RawTok, Token &PPTok) {
|
||||
// If two tokens have the same kind and the same identifier info, they are
|
||||
// obviously the same.
|
||||
if (PPTok.getKind() == RawTok.getKind() &&
|
||||
PPTok.getIdentifierInfo() == RawTok.getIdentifierInfo())
|
||||
return true;
|
||||
|
||||
// Otherwise, if they are different but have the same identifier info, they
|
||||
// are also considered to be the same. This allows keywords and raw lexed
|
||||
// identifiers with the same name to be treated the same.
|
||||
if (PPTok.getIdentifierInfo() &&
|
||||
PPTok.getIdentifierInfo() == RawTok.getIdentifierInfo())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/// GetNextRawTok - Return the next raw token in the stream, skipping over
|
||||
/// comments if ReturnComment is false.
|
||||
static const Token &GetNextRawTok(const std::vector<Token> &RawTokens,
|
||||
unsigned &CurTok, bool ReturnComment) {
|
||||
assert(CurTok < RawTokens.size() && "Overran eof!");
|
||||
|
||||
// If the client doesn't want comments and we have one, skip it.
|
||||
if (!ReturnComment && RawTokens[CurTok].is(tok::comment))
|
||||
++CurTok;
|
||||
|
||||
return RawTokens[CurTok++];
|
||||
}
|
||||
|
||||
|
||||
/// LexRawTokensFromMainFile - Lets all the raw tokens from the main file into
|
||||
/// the specified vector.
|
||||
static void LexRawTokensFromMainFile(Preprocessor &PP,
|
||||
std::vector<Token> &RawTokens) {
|
||||
SourceManager &SM = PP.getSourceManager();
|
||||
|
||||
// Create a lexer to lex all the tokens of the main file in raw mode. Even
|
||||
// though it is in raw mode, it will not return comments.
|
||||
Lexer RawLex(SM.getMainFileID(), SM, PP.getLangOptions());
|
||||
|
||||
// Switch on comment lexing because we really do want them.
|
||||
RawLex.SetCommentRetentionState(true);
|
||||
|
||||
Token RawTok;
|
||||
do {
|
||||
RawLex.LexFromRawLexer(RawTok);
|
||||
|
||||
// If we have an identifier with no identifier info for our raw token, look
|
||||
// up the indentifier info. This is important for equality comparison of
|
||||
// identifier tokens.
|
||||
if (RawTok.is(tok::identifier) && !RawTok.getIdentifierInfo())
|
||||
RawTok.setIdentifierInfo(PP.LookUpIdentifierInfo(RawTok));
|
||||
|
||||
RawTokens.push_back(RawTok);
|
||||
} while (RawTok.isNot(tok::eof));
|
||||
}
|
||||
|
||||
|
||||
/// RewriteMacrosInInput - Implement -rewrite-macros mode.
|
||||
void clang::RewriteMacrosInInput(Preprocessor &PP,const std::string &InFileName,
|
||||
const std::string &OutFileName) {
|
||||
SourceManager &SM = PP.getSourceManager();
|
||||
|
||||
Rewriter Rewrite;
|
||||
Rewrite.setSourceMgr(SM);
|
||||
RewriteBuffer &RB = Rewrite.getEditBuffer(SM.getMainFileID());
|
||||
|
||||
std::vector<Token> RawTokens;
|
||||
LexRawTokensFromMainFile(PP, RawTokens);
|
||||
unsigned CurRawTok = 0;
|
||||
Token RawTok = GetNextRawTok(RawTokens, CurRawTok, false);
|
||||
|
||||
|
||||
// Get the first preprocessing token.
|
||||
PP.EnterMainSourceFile();
|
||||
Token PPTok;
|
||||
PP.Lex(PPTok);
|
||||
|
||||
// Preprocess the input file in parallel with raw lexing the main file. Ignore
|
||||
// all tokens that are preprocessed from a file other than the main file (e.g.
|
||||
// a header). If we see tokens that are in the preprocessed file but not the
|
||||
// lexed file, we have a macro expansion. If we see tokens in the lexed file
|
||||
// that aren't in the preprocessed view, we have macros that expand to no
|
||||
// tokens, or macro arguments etc.
|
||||
while (RawTok.isNot(tok::eof) || PPTok.isNot(tok::eof)) {
|
||||
SourceLocation PPLoc = SM.getInstantiationLoc(PPTok.getLocation());
|
||||
|
||||
// If PPTok is from a different source file, ignore it.
|
||||
if (!SM.isFromMainFile(PPLoc)) {
|
||||
PP.Lex(PPTok);
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the raw file hits a preprocessor directive, they will be extra tokens
|
||||
// in the raw file that don't exist in the preprocsesed file. However, we
|
||||
// choose to preserve them in the output file and otherwise handle them
|
||||
// specially.
|
||||
if (RawTok.is(tok::hash) && RawTok.isAtStartOfLine()) {
|
||||
// If this is a #warning directive or #pragma mark (GNU extensions),
|
||||
// comment the line out.
|
||||
if (RawTokens[CurRawTok].is(tok::identifier)) {
|
||||
const IdentifierInfo *II = RawTokens[CurRawTok].getIdentifierInfo();
|
||||
if (!strcmp(II->getName(), "warning")) {
|
||||
// Comment out #warning.
|
||||
RB.InsertTextAfter(SM.getFileOffset(RawTok.getLocation()), "//", 2);
|
||||
} else if (!strcmp(II->getName(), "pragma") &&
|
||||
RawTokens[CurRawTok+1].is(tok::identifier) &&
|
||||
!strcmp(RawTokens[CurRawTok+1].getIdentifierInfo()->getName(),
|
||||
"mark")){
|
||||
// Comment out #pragma mark.
|
||||
RB.InsertTextAfter(SM.getFileOffset(RawTok.getLocation()), "//", 2);
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, if this is a #include or some other directive, just leave it
|
||||
// in the file by skipping over the line.
|
||||
RawTok = GetNextRawTok(RawTokens, CurRawTok, false);
|
||||
while (!RawTok.isAtStartOfLine() && RawTok.isNot(tok::eof))
|
||||
RawTok = GetNextRawTok(RawTokens, CurRawTok, false);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Okay, both tokens are from the same file. Get their offsets from the
|
||||
// start of the file.
|
||||
unsigned PPOffs = SM.getFileOffset(PPLoc);
|
||||
unsigned RawOffs = SM.getFileOffset(RawTok.getLocation());
|
||||
|
||||
// If the offsets are the same and the token kind is the same, ignore them.
|
||||
if (PPOffs == RawOffs && isSameToken(RawTok, PPTok)) {
|
||||
RawTok = GetNextRawTok(RawTokens, CurRawTok, false);
|
||||
PP.Lex(PPTok);
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the PP token is farther along than the raw token, something was
|
||||
// deleted. Comment out the raw token.
|
||||
if (RawOffs <= PPOffs) {
|
||||
// Comment out a whole run of tokens instead of bracketing each one with
|
||||
// comments. Add a leading space if RawTok didn't have one.
|
||||
bool HasSpace = RawTok.hasLeadingSpace();
|
||||
RB.InsertTextAfter(RawOffs, " /*"+HasSpace, 2+!HasSpace);
|
||||
unsigned EndPos;
|
||||
|
||||
do {
|
||||
EndPos = RawOffs+RawTok.getLength();
|
||||
|
||||
RawTok = GetNextRawTok(RawTokens, CurRawTok, true);
|
||||
RawOffs = SM.getFileOffset(RawTok.getLocation());
|
||||
|
||||
if (RawTok.is(tok::comment)) {
|
||||
// Skip past the comment.
|
||||
RawTok = GetNextRawTok(RawTokens, CurRawTok, false);
|
||||
break;
|
||||
}
|
||||
|
||||
} while (RawOffs <= PPOffs && !RawTok.isAtStartOfLine() &&
|
||||
(PPOffs != RawOffs || !isSameToken(RawTok, PPTok)));
|
||||
|
||||
RB.InsertTextBefore(EndPos, "*/", 2);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Otherwise, there was a replacement an expansion. Insert the new token
|
||||
// in the output buffer. Insert the whole run of new tokens at once to get
|
||||
// them in the right order.
|
||||
unsigned InsertPos = PPOffs;
|
||||
std::string Expansion;
|
||||
while (PPOffs < RawOffs) {
|
||||
Expansion += ' ' + PP.getSpelling(PPTok);
|
||||
PP.Lex(PPTok);
|
||||
PPLoc = SM.getInstantiationLoc(PPTok.getLocation());
|
||||
PPOffs = SM.getFileOffset(PPLoc);
|
||||
}
|
||||
Expansion += ' ';
|
||||
RB.InsertTextBefore(InsertPos, &Expansion[0], Expansion.size());
|
||||
}
|
||||
|
||||
// Create the output file.
|
||||
llvm::OwningPtr<llvm::raw_ostream> OwnedStream;
|
||||
llvm::raw_ostream *OutFile;
|
||||
if (OutFileName == "-") {
|
||||
OutFile = &llvm::outs();
|
||||
} else if (!OutFileName.empty()) {
|
||||
std::string Err;
|
||||
OutFile = new llvm::raw_fd_ostream(OutFileName.c_str(), false, Err);
|
||||
OwnedStream.reset(OutFile);
|
||||
} else if (InFileName == "-") {
|
||||
OutFile = &llvm::outs();
|
||||
} else {
|
||||
llvm::sys::Path Path(InFileName);
|
||||
Path.eraseSuffix();
|
||||
Path.appendSuffix("cpp");
|
||||
std::string Err;
|
||||
OutFile = new llvm::raw_fd_ostream(Path.toString().c_str(), false, Err);
|
||||
OwnedStream.reset(OutFile);
|
||||
}
|
||||
|
||||
// Get the buffer corresponding to MainFileID. If we haven't changed it, then
|
||||
// we are done.
|
||||
if (const RewriteBuffer *RewriteBuf =
|
||||
Rewrite.getRewriteBufferFor(SM.getMainFileID())) {
|
||||
//printf("Changed:\n");
|
||||
*OutFile << std::string(RewriteBuf->begin(), RewriteBuf->end());
|
||||
} else {
|
||||
fprintf(stderr, "No changes\n");
|
||||
}
|
||||
OutFile->flush();
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,40 +0,0 @@
|
||||
//===--- RewriteTest.cpp - Rewriter playground ----------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This is a testbed.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang.h"
|
||||
#include "clang/Lex/Preprocessor.h"
|
||||
#include "clang/Rewrite/TokenRewriter.h"
|
||||
#include <iostream>
|
||||
|
||||
void clang::DoRewriteTest(Preprocessor &PP, const std::string &InFileName,
|
||||
const std::string &OutFileName) {
|
||||
SourceManager &SM = PP.getSourceManager();
|
||||
const LangOptions &LangOpts = PP.getLangOptions();
|
||||
|
||||
TokenRewriter Rewriter(SM.getMainFileID(), SM, LangOpts);
|
||||
|
||||
// Throw <i> </i> tags around comments.
|
||||
for (TokenRewriter::token_iterator I = Rewriter.token_begin(),
|
||||
E = Rewriter.token_end(); I != E; ++I) {
|
||||
if (I->isNot(tok::comment)) continue;
|
||||
|
||||
Rewriter.AddTokenBefore(I, "<i>");
|
||||
Rewriter.AddTokenAfter(I, "</i>");
|
||||
}
|
||||
|
||||
|
||||
// Print out the output.
|
||||
for (TokenRewriter::token_iterator I = Rewriter.token_begin(),
|
||||
E = Rewriter.token_end(); I != E; ++I)
|
||||
std::cout << PP.getSpelling(*I);
|
||||
}
|
||||
@@ -1,193 +0,0 @@
|
||||
//===--- SerializationTest.cpp - Experimental Object Serialization --------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements prototype code for serialization of objects in clang.
|
||||
// It is not intended yet for public use, but simply is a placeholder to
|
||||
// experiment with new serialization features. Serialization will eventually
|
||||
// be integrated as a proper component of the clang libraries.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/AST/ASTConsumer.h"
|
||||
#include "clang/AST/CFG.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang.h"
|
||||
#include "ASTConsumers.h"
|
||||
#include "clang/AST/TranslationUnit.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
#include "llvm/Support/Streams.h"
|
||||
#include <fstream>
|
||||
#include <cstring>
|
||||
using namespace clang;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Driver code.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace {
|
||||
|
||||
class SerializationTest : public ASTConsumer {
|
||||
Diagnostic &Diags;
|
||||
FileManager &FMgr;
|
||||
public:
|
||||
SerializationTest(Diagnostic &d, FileManager& fmgr)
|
||||
: Diags(d), FMgr(fmgr) {}
|
||||
|
||||
~SerializationTest() {}
|
||||
|
||||
virtual void HandleTranslationUnit(TranslationUnit& TU);
|
||||
|
||||
private:
|
||||
bool Serialize(llvm::sys::Path& Filename, llvm::sys::Path& FNameDeclPrint,
|
||||
TranslationUnit& TU);
|
||||
|
||||
bool Deserialize(llvm::sys::Path& Filename, llvm::sys::Path& FNameDeclPrint);
|
||||
};
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
ASTConsumer*
|
||||
clang::CreateSerializationTest(Diagnostic &Diags, FileManager& FMgr) {
|
||||
return new SerializationTest(Diags, FMgr);
|
||||
}
|
||||
|
||||
|
||||
bool SerializationTest::Serialize(llvm::sys::Path& Filename,
|
||||
llvm::sys::Path& FNameDeclPrint,
|
||||
TranslationUnit& TU) {
|
||||
{
|
||||
// Pretty-print the decls to a temp file.
|
||||
std::string Err;
|
||||
llvm::raw_fd_ostream DeclPP(FNameDeclPrint.c_str(), true, Err);
|
||||
assert (Err.empty() && "Could not open file for printing out decls.");
|
||||
llvm::OwningPtr<ASTConsumer> FilePrinter(CreateASTPrinter(&DeclPP));
|
||||
|
||||
for (TranslationUnit::iterator I=TU.begin(), E=TU.end(); I!=E; ++I)
|
||||
FilePrinter->HandleTopLevelDecl(*I);
|
||||
}
|
||||
|
||||
// Serialize the translation unit.
|
||||
return EmitASTBitcodeFile(TU,Filename);
|
||||
}
|
||||
|
||||
bool SerializationTest::Deserialize(llvm::sys::Path& Filename,
|
||||
llvm::sys::Path& FNameDeclPrint) {
|
||||
|
||||
// Deserialize the translation unit.
|
||||
TranslationUnit* NewTU = ReadASTBitcodeFile(Filename, FMgr);
|
||||
|
||||
if (!NewTU)
|
||||
return false;
|
||||
|
||||
{
|
||||
// Pretty-print the deserialized decls to a temp file.
|
||||
std::string Err;
|
||||
llvm::raw_fd_ostream DeclPP(FNameDeclPrint.c_str(), true, Err);
|
||||
assert (Err.empty() && "Could not open file for printing out decls.");
|
||||
llvm::OwningPtr<ASTConsumer> FilePrinter(CreateASTPrinter(&DeclPP));
|
||||
|
||||
for (TranslationUnit::iterator I=NewTU->begin(), E=NewTU->end(); I!=E; ++I)
|
||||
FilePrinter->HandleTopLevelDecl(*I);
|
||||
}
|
||||
|
||||
delete NewTU;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace {
|
||||
class TmpDirJanitor {
|
||||
llvm::sys::Path& Dir;
|
||||
public:
|
||||
explicit TmpDirJanitor(llvm::sys::Path& dir) : Dir(dir) {}
|
||||
|
||||
~TmpDirJanitor() {
|
||||
llvm::cerr << "Removing: " << Dir.c_str() << '\n';
|
||||
Dir.eraseFromDisk(true);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void SerializationTest::HandleTranslationUnit(TranslationUnit& TU) {
|
||||
|
||||
std::string ErrMsg;
|
||||
llvm::sys::Path Dir = llvm::sys::Path::GetTemporaryDirectory(&ErrMsg);
|
||||
|
||||
if (Dir.isEmpty()) {
|
||||
llvm::cerr << "Error: " << ErrMsg << "\n";
|
||||
return;
|
||||
}
|
||||
|
||||
TmpDirJanitor RemoveTmpOnExit(Dir);
|
||||
|
||||
llvm::sys::Path FNameDeclBefore = Dir;
|
||||
FNameDeclBefore.appendComponent("test.decl_before.txt");
|
||||
|
||||
if (FNameDeclBefore.makeUnique(true,&ErrMsg)) {
|
||||
llvm::cerr << "Error: " << ErrMsg << "\n";
|
||||
return;
|
||||
}
|
||||
|
||||
llvm::sys::Path FNameDeclAfter = Dir;
|
||||
FNameDeclAfter.appendComponent("test.decl_after.txt");
|
||||
|
||||
if (FNameDeclAfter.makeUnique(true,&ErrMsg)) {
|
||||
llvm::cerr << "Error: " << ErrMsg << "\n";
|
||||
return;
|
||||
}
|
||||
|
||||
llvm::sys::Path ASTFilename = Dir;
|
||||
ASTFilename.appendComponent("test.ast");
|
||||
|
||||
if (ASTFilename.makeUnique(true,&ErrMsg)) {
|
||||
llvm::cerr << "Error: " << ErrMsg << "\n";
|
||||
return;
|
||||
}
|
||||
|
||||
// Serialize and then deserialize the ASTs.
|
||||
bool status = Serialize(ASTFilename, FNameDeclBefore, TU);
|
||||
assert (status && "Serialization failed.");
|
||||
status = Deserialize(ASTFilename, FNameDeclAfter);
|
||||
assert (status && "Deserialization failed.");
|
||||
|
||||
// Read both pretty-printed files and compare them.
|
||||
|
||||
using llvm::MemoryBuffer;
|
||||
|
||||
llvm::OwningPtr<MemoryBuffer>
|
||||
MBufferSer(MemoryBuffer::getFile(FNameDeclBefore.c_str()));
|
||||
|
||||
if(!MBufferSer) {
|
||||
llvm::cerr << "ERROR: Cannot read pretty-printed file (pre-pickle).\n";
|
||||
return;
|
||||
}
|
||||
|
||||
llvm::OwningPtr<MemoryBuffer>
|
||||
MBufferDSer(MemoryBuffer::getFile(FNameDeclAfter.c_str()));
|
||||
|
||||
if(!MBufferDSer) {
|
||||
llvm::cerr << "ERROR: Cannot read pretty-printed file (post-pickle).\n";
|
||||
return;
|
||||
}
|
||||
|
||||
const char *p1 = MBufferSer->getBufferStart();
|
||||
const char *e1 = MBufferSer->getBufferEnd();
|
||||
const char *p2 = MBufferDSer->getBufferStart();
|
||||
const char *e2 = MBufferDSer->getBufferEnd();
|
||||
|
||||
if (MBufferSer->getBufferSize() == MBufferDSer->getBufferSize())
|
||||
for ( ; p1 != e1 ; ++p1, ++p2 )
|
||||
if (*p1 != *p2) break;
|
||||
|
||||
if (p1 != e1 || p2 != e2 )
|
||||
llvm::cerr << "ERROR: Pretty-printed files are not the same.\n";
|
||||
else
|
||||
llvm::cerr << "SUCCESS: Pretty-printed files are the same.\n";
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,59 +0,0 @@
|
||||
//===--- clang.h - C-Language Front-end -----------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This is the header file that pulls together the top-level driver.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_CLANG_H
|
||||
#define LLVM_CLANG_CLANG_H
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace clang {
|
||||
class Preprocessor;
|
||||
class MinimalAction;
|
||||
class TargetInfo;
|
||||
class Diagnostic;
|
||||
class ASTConsumer;
|
||||
class IdentifierTable;
|
||||
class SourceManager;
|
||||
|
||||
/// DoPrintPreprocessedInput - Implement -E mode.
|
||||
void DoPrintPreprocessedInput(Preprocessor &PP, const std::string& OutFile);
|
||||
|
||||
/// RewriteMacrosInInput - Implement -rewrite-macros mode.
|
||||
void RewriteMacrosInInput(Preprocessor &PP, const std::string &InFileName,
|
||||
const std::string& OutFile);
|
||||
|
||||
void DoRewriteTest(Preprocessor &PP, const std::string &InFileName,
|
||||
const std::string &OutFileName);
|
||||
|
||||
|
||||
/// CreatePrintParserActionsAction - Return the actions implementation that
|
||||
/// implements the -parse-print-callbacks option.
|
||||
MinimalAction *CreatePrintParserActionsAction(Preprocessor &PP);
|
||||
|
||||
/// CheckDiagnostics - Gather the expected diagnostics and check them.
|
||||
bool CheckDiagnostics(Preprocessor &PP);
|
||||
|
||||
/// CreateDependencyFileGen - Create dependency file generator.
|
||||
/// This is only done if either -MD or -MMD has been specified.
|
||||
bool CreateDependencyFileGen(Preprocessor *PP,
|
||||
std::string &OutputFile,
|
||||
const std::string &InputFile,
|
||||
const char *&ErrStr);
|
||||
|
||||
/// CacheTokens - Cache tokens for use with PCH.
|
||||
void CacheTokens(Preprocessor& PP, const std::string& OutFile);
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
@@ -1,2 +0,0 @@
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
@@ -1,639 +0,0 @@
|
||||
/* Test for integer constant types. */
|
||||
|
||||
/* Origin: Joseph Myers <jsm28@cam.ac.uk>. */
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-std=iso9899:1999 -pedantic-errors" } */
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
/* Assertion that constant C is of type T. */
|
||||
#define ASSERT_CONST_TYPE(C, T) \
|
||||
do { \
|
||||
typedef T type; \
|
||||
typedef type **typepp; \
|
||||
typedef __typeof__((C)) ctype; \
|
||||
typedef ctype **ctypepp; \
|
||||
typepp x = 0; \
|
||||
ctypepp y = 0; \
|
||||
x = y; \
|
||||
y = x; \
|
||||
} while (0)
|
||||
|
||||
/* (T *) if E is zero, (void *) otherwise. */
|
||||
#define type_if_not(T, E) __typeof__(0 ? (T *)0 : (void *)(E))
|
||||
|
||||
/* (T *) if E is nonzero, (void *) otherwise. */
|
||||
#define type_if(T, E) type_if_not(T, !(E))
|
||||
|
||||
/* Combine pointer types, all but one (void *). */
|
||||
#define type_comb2(T1, T2) __typeof__(0 ? (T1)0 : (T2)0)
|
||||
#define type_comb3(T1, T2, T3) type_comb2(T1, type_comb2(T2, T3))
|
||||
#define type_comb4(T1, T2, T3, T4) \
|
||||
type_comb2(T1, type_comb2(T2, type_comb2(T3, T4)))
|
||||
#define type_comb6(T1, T2, T3, T4, T5, T6) \
|
||||
type_comb2(T1, \
|
||||
type_comb2(T2, \
|
||||
type_comb2(T3, \
|
||||
type_comb2(T4, \
|
||||
type_comb2(T5, T6)))))
|
||||
|
||||
/* (T1 *) if E1, otherwise (T2 *) if E2. */
|
||||
#define first_of2p(T1, E1, T2, E2) type_comb2(type_if(T1, (E1)), \
|
||||
type_if(T2, (!(E1) && (E2))))
|
||||
/* (T1 *) if E1, otherwise (T2 *) if E2, otherwise (T3 *) if E3. */
|
||||
#define first_of3p(T1, E1, T2, E2, T3, E3) \
|
||||
type_comb3(type_if(T1, (E1)), \
|
||||
type_if(T2, (!(E1) && (E2))), \
|
||||
type_if(T3, (!(E1) && !(E2) && (E3))))
|
||||
/* (T1 *) if E1, otherwise (T2 *) if E2, otherwise (T3 *) if E3, otherwise
|
||||
(T4 *) if E4. */
|
||||
#define first_of4p(T1, E1, T2, E2, T3, E3, T4, E4) \
|
||||
type_comb4(type_if(T1, (E1)), \
|
||||
type_if(T2, (!(E1) && (E2))), \
|
||||
type_if(T3, (!(E1) && !(E2) && (E3))), \
|
||||
type_if(T4, (!(E1) && !(E2) && !(E3) && (E4))))
|
||||
/* (T1 *) if E1, otherwise (T2 *) if E2, otherwise (T3 *) if E3, otherwise
|
||||
(T4 *) if E4, otherwise (T5 *) if E5, otherwise (T6 *) if E6. */
|
||||
#define first_of6p(T1, E1, T2, E2, T3, E3, T4, E4, T5, E5, T6, E6) \
|
||||
type_comb6(type_if(T1, (E1)), \
|
||||
type_if(T2, (!(E1) && (E2))), \
|
||||
type_if(T3, (!(E1) && !(E2) && (E3))), \
|
||||
type_if(T4, (!(E1) && !(E2) && !(E3) && (E4))), \
|
||||
type_if(T5, (!(E1) && !(E2) && !(E3) && !(E4) && (E5))), \
|
||||
type_if(T6, (!(E1) && !(E2) && !(E3) \
|
||||
&& !(E4) && !(E5) && (E6))))
|
||||
|
||||
/* Likewise, but return the original type rather than a pointer type. */
|
||||
#define first_of2(T1, E1, T2, E2) \
|
||||
__typeof__(*((first_of2p(T1, (E1), T2, (E2)))0))
|
||||
#define first_of3(T1, E1, T2, E2, T3, E3) \
|
||||
__typeof__(*((first_of3p(T1, (E1), T2, (E2), T3, (E3)))0))
|
||||
#define first_of4(T1, E1, T2, E2, T3, E3, T4, E4) \
|
||||
__typeof__(*((first_of4p(T1, (E1), T2, (E2), T3, (E3), T4, (E4)))0))
|
||||
#define first_of6(T1, E1, T2, E2, T3, E3, T4, E4, T5, E5, T6, E6) \
|
||||
__typeof__(*((first_of6p(T1, (E1), T2, (E2), T3, (E3), \
|
||||
T4, (E4), T5, (E5), T6, (E6)))0))
|
||||
|
||||
/* Types of constants according to the C99 rules. */
|
||||
#define C99_UNSUF_DEC_TYPE(C) \
|
||||
first_of3(int, (C) <= INT_MAX, \
|
||||
long int, (C) <= LONG_MAX, \
|
||||
long long int, (C) <= LLONG_MAX)
|
||||
#define C99_UNSUF_OCTHEX_TYPE(C) \
|
||||
first_of6(int, (C) <= INT_MAX, \
|
||||
unsigned int, (C) <= UINT_MAX, \
|
||||
long int, (C) <= LONG_MAX, \
|
||||
unsigned long int, (C) <= ULONG_MAX, \
|
||||
long long int, (C) <= LLONG_MAX, \
|
||||
unsigned long long int, (C) <= ULLONG_MAX)
|
||||
#define C99_SUFu_TYPE(C) \
|
||||
first_of3(unsigned int, (C) <= UINT_MAX, \
|
||||
unsigned long int, (C) <= ULONG_MAX, \
|
||||
unsigned long long int, (C) <= ULLONG_MAX)
|
||||
#define C99_SUFl_DEC_TYPE(C) \
|
||||
first_of2(long int, (C) <= LONG_MAX, \
|
||||
long long int, (C) <= LLONG_MAX)
|
||||
#define C99_SUFl_OCTHEX_TYPE(C) \
|
||||
first_of4(long int, (C) <= LONG_MAX, \
|
||||
unsigned long int, (C) <= ULONG_MAX, \
|
||||
long long int, (C) <= LLONG_MAX, \
|
||||
unsigned long long int, (C) <= ULLONG_MAX)
|
||||
#define C99_SUFul_TYPE(C) \
|
||||
first_of2(unsigned long int, (C) <= ULONG_MAX, \
|
||||
unsigned long long int, (C) <= ULLONG_MAX)
|
||||
#define C99_SUFll_OCTHEX_TYPE(C) \
|
||||
first_of2(long long int, (C) <= LLONG_MAX, \
|
||||
unsigned long long int, (C) <= ULLONG_MAX)
|
||||
|
||||
/* Checks that constants have correct type. */
|
||||
#define CHECK_UNSUF_DEC_TYPE(C) ASSERT_CONST_TYPE((C), C99_UNSUF_DEC_TYPE((C)))
|
||||
#define CHECK_UNSUF_OCTHEX_TYPE(C) \
|
||||
ASSERT_CONST_TYPE((C), C99_UNSUF_OCTHEX_TYPE((C)))
|
||||
#define CHECK_SUFu_TYPE(C) ASSERT_CONST_TYPE((C), C99_SUFu_TYPE((C)))
|
||||
#define CHECK_SUFl_DEC_TYPE(C) ASSERT_CONST_TYPE((C), C99_SUFl_DEC_TYPE((C)))
|
||||
#define CHECK_SUFl_OCTHEX_TYPE(C) \
|
||||
ASSERT_CONST_TYPE((C), C99_SUFl_OCTHEX_TYPE((C)))
|
||||
#define CHECK_SUFul_TYPE(C) ASSERT_CONST_TYPE((C), C99_SUFul_TYPE((C)))
|
||||
#define CHECK_SUFll_DEC_TYPE(C) ASSERT_CONST_TYPE((C), long long int)
|
||||
#define CHECK_SUFll_OCTHEX_TYPE(C) \
|
||||
ASSERT_CONST_TYPE((C), C99_SUFll_OCTHEX_TYPE((C)))
|
||||
#define CHECK_SUFull_TYPE(C) ASSERT_CONST_TYPE((C), unsigned long long int)
|
||||
|
||||
/* Check a decimal value, with all suffixes. */
|
||||
#define CHECK_DEC_CONST(C) \
|
||||
CHECK_UNSUF_DEC_TYPE(C); \
|
||||
CHECK_SUFu_TYPE(C##u); \
|
||||
CHECK_SUFu_TYPE(C##U); \
|
||||
CHECK_SUFl_DEC_TYPE(C##l); \
|
||||
CHECK_SUFl_DEC_TYPE(C##L); \
|
||||
CHECK_SUFul_TYPE(C##ul); \
|
||||
CHECK_SUFul_TYPE(C##uL); \
|
||||
CHECK_SUFul_TYPE(C##Ul); \
|
||||
CHECK_SUFul_TYPE(C##UL); \
|
||||
CHECK_SUFll_DEC_TYPE(C##ll); \
|
||||
CHECK_SUFll_DEC_TYPE(C##LL); \
|
||||
CHECK_SUFull_TYPE(C##ull); \
|
||||
CHECK_SUFull_TYPE(C##uLL); \
|
||||
CHECK_SUFull_TYPE(C##Ull); \
|
||||
CHECK_SUFull_TYPE(C##ULL);
|
||||
|
||||
/* Check an octal or hexadecimal value, with all suffixes. */
|
||||
#define CHECK_OCTHEX_CONST(C) \
|
||||
CHECK_UNSUF_OCTHEX_TYPE(C); \
|
||||
CHECK_SUFu_TYPE(C##u); \
|
||||
CHECK_SUFu_TYPE(C##U); \
|
||||
CHECK_SUFl_OCTHEX_TYPE(C##l); \
|
||||
CHECK_SUFl_OCTHEX_TYPE(C##L); \
|
||||
CHECK_SUFul_TYPE(C##ul); \
|
||||
CHECK_SUFul_TYPE(C##uL); \
|
||||
CHECK_SUFul_TYPE(C##Ul); \
|
||||
CHECK_SUFul_TYPE(C##UL); \
|
||||
CHECK_SUFll_OCTHEX_TYPE(C##ll); \
|
||||
CHECK_SUFll_OCTHEX_TYPE(C##LL); \
|
||||
CHECK_SUFull_TYPE(C##ull); \
|
||||
CHECK_SUFull_TYPE(C##uLL); \
|
||||
CHECK_SUFull_TYPE(C##Ull); \
|
||||
CHECK_SUFull_TYPE(C##ULL);
|
||||
|
||||
#define CHECK_OCT_CONST(C) CHECK_OCTHEX_CONST(C)
|
||||
#define CHECK_HEX_CONST(C) \
|
||||
CHECK_OCTHEX_CONST(0x##C); \
|
||||
CHECK_OCTHEX_CONST(0X##C);
|
||||
|
||||
/* True iff "long long" is at least B bits. This presumes that (B-2)/3 is at
|
||||
most 63. */
|
||||
#define LLONG_AT_LEAST(B) \
|
||||
(LLONG_MAX >> ((B)-2)/3 >> ((B)-2)/3 \
|
||||
>> ((B)-2 - ((B)-2)/3 - ((B)-2)/3))
|
||||
|
||||
#define LLONG_HAS_BITS(B) (LLONG_AT_LEAST((B)) && !LLONG_AT_LEAST((B) + 1))
|
||||
|
||||
void
|
||||
foo (void)
|
||||
{
|
||||
/* Decimal. */
|
||||
/* Check all 2^n and 2^n - 1 up to 2^71 - 1. */
|
||||
CHECK_DEC_CONST(1);
|
||||
CHECK_DEC_CONST(2);
|
||||
CHECK_DEC_CONST(3);
|
||||
CHECK_DEC_CONST(4);
|
||||
CHECK_DEC_CONST(7);
|
||||
CHECK_DEC_CONST(8);
|
||||
CHECK_DEC_CONST(15);
|
||||
CHECK_DEC_CONST(16);
|
||||
CHECK_DEC_CONST(31);
|
||||
CHECK_DEC_CONST(32);
|
||||
CHECK_DEC_CONST(63);
|
||||
CHECK_DEC_CONST(64);
|
||||
CHECK_DEC_CONST(127);
|
||||
CHECK_DEC_CONST(128);
|
||||
CHECK_DEC_CONST(255);
|
||||
CHECK_DEC_CONST(256);
|
||||
CHECK_DEC_CONST(511);
|
||||
CHECK_DEC_CONST(512);
|
||||
CHECK_DEC_CONST(1023);
|
||||
CHECK_DEC_CONST(1024);
|
||||
CHECK_DEC_CONST(2047);
|
||||
CHECK_DEC_CONST(2048);
|
||||
CHECK_DEC_CONST(4095);
|
||||
CHECK_DEC_CONST(4096);
|
||||
CHECK_DEC_CONST(8191);
|
||||
CHECK_DEC_CONST(8192);
|
||||
CHECK_DEC_CONST(16383);
|
||||
CHECK_DEC_CONST(16384);
|
||||
CHECK_DEC_CONST(32767);
|
||||
CHECK_DEC_CONST(32768);
|
||||
CHECK_DEC_CONST(65535);
|
||||
CHECK_DEC_CONST(65536);
|
||||
CHECK_DEC_CONST(131071);
|
||||
CHECK_DEC_CONST(131072);
|
||||
CHECK_DEC_CONST(262143);
|
||||
CHECK_DEC_CONST(262144);
|
||||
CHECK_DEC_CONST(524287);
|
||||
CHECK_DEC_CONST(524288);
|
||||
CHECK_DEC_CONST(1048575);
|
||||
CHECK_DEC_CONST(1048576);
|
||||
CHECK_DEC_CONST(2097151);
|
||||
CHECK_DEC_CONST(2097152);
|
||||
CHECK_DEC_CONST(4194303);
|
||||
CHECK_DEC_CONST(4194304);
|
||||
CHECK_DEC_CONST(8388607);
|
||||
CHECK_DEC_CONST(8388608);
|
||||
CHECK_DEC_CONST(16777215);
|
||||
CHECK_DEC_CONST(16777216);
|
||||
CHECK_DEC_CONST(33554431);
|
||||
CHECK_DEC_CONST(33554432);
|
||||
CHECK_DEC_CONST(67108863);
|
||||
CHECK_DEC_CONST(67108864);
|
||||
CHECK_DEC_CONST(134217727);
|
||||
CHECK_DEC_CONST(134217728);
|
||||
CHECK_DEC_CONST(268435455);
|
||||
CHECK_DEC_CONST(268435456);
|
||||
CHECK_DEC_CONST(536870911);
|
||||
CHECK_DEC_CONST(536870912);
|
||||
CHECK_DEC_CONST(1073741823);
|
||||
CHECK_DEC_CONST(1073741824);
|
||||
CHECK_DEC_CONST(2147483647);
|
||||
CHECK_DEC_CONST(2147483648);
|
||||
CHECK_DEC_CONST(4294967295);
|
||||
CHECK_DEC_CONST(4294967296);
|
||||
CHECK_DEC_CONST(8589934591);
|
||||
CHECK_DEC_CONST(8589934592);
|
||||
CHECK_DEC_CONST(17179869183);
|
||||
CHECK_DEC_CONST(17179869184);
|
||||
CHECK_DEC_CONST(34359738367);
|
||||
CHECK_DEC_CONST(34359738368);
|
||||
CHECK_DEC_CONST(68719476735);
|
||||
CHECK_DEC_CONST(68719476736);
|
||||
CHECK_DEC_CONST(137438953471);
|
||||
CHECK_DEC_CONST(137438953472);
|
||||
CHECK_DEC_CONST(274877906943);
|
||||
CHECK_DEC_CONST(274877906944);
|
||||
CHECK_DEC_CONST(549755813887);
|
||||
CHECK_DEC_CONST(549755813888);
|
||||
CHECK_DEC_CONST(1099511627775);
|
||||
CHECK_DEC_CONST(1099511627776);
|
||||
CHECK_DEC_CONST(2199023255551);
|
||||
CHECK_DEC_CONST(2199023255552);
|
||||
CHECK_DEC_CONST(4398046511103);
|
||||
CHECK_DEC_CONST(4398046511104);
|
||||
CHECK_DEC_CONST(8796093022207);
|
||||
CHECK_DEC_CONST(8796093022208);
|
||||
CHECK_DEC_CONST(17592186044415);
|
||||
CHECK_DEC_CONST(17592186044416);
|
||||
CHECK_DEC_CONST(35184372088831);
|
||||
CHECK_DEC_CONST(35184372088832);
|
||||
CHECK_DEC_CONST(70368744177663);
|
||||
CHECK_DEC_CONST(70368744177664);
|
||||
CHECK_DEC_CONST(140737488355327);
|
||||
CHECK_DEC_CONST(140737488355328);
|
||||
CHECK_DEC_CONST(281474976710655);
|
||||
CHECK_DEC_CONST(281474976710656);
|
||||
CHECK_DEC_CONST(562949953421311);
|
||||
CHECK_DEC_CONST(562949953421312);
|
||||
CHECK_DEC_CONST(1125899906842623);
|
||||
CHECK_DEC_CONST(1125899906842624);
|
||||
CHECK_DEC_CONST(2251799813685247);
|
||||
CHECK_DEC_CONST(2251799813685248);
|
||||
CHECK_DEC_CONST(4503599627370495);
|
||||
CHECK_DEC_CONST(4503599627370496);
|
||||
CHECK_DEC_CONST(9007199254740991);
|
||||
CHECK_DEC_CONST(9007199254740992);
|
||||
CHECK_DEC_CONST(18014398509481983);
|
||||
CHECK_DEC_CONST(18014398509481984);
|
||||
CHECK_DEC_CONST(36028797018963967);
|
||||
CHECK_DEC_CONST(36028797018963968);
|
||||
CHECK_DEC_CONST(72057594037927935);
|
||||
CHECK_DEC_CONST(72057594037927936);
|
||||
CHECK_DEC_CONST(144115188075855871);
|
||||
CHECK_DEC_CONST(144115188075855872);
|
||||
CHECK_DEC_CONST(288230376151711743);
|
||||
CHECK_DEC_CONST(288230376151711744);
|
||||
CHECK_DEC_CONST(576460752303423487);
|
||||
CHECK_DEC_CONST(576460752303423488);
|
||||
CHECK_DEC_CONST(1152921504606846975);
|
||||
CHECK_DEC_CONST(1152921504606846976);
|
||||
CHECK_DEC_CONST(2305843009213693951);
|
||||
CHECK_DEC_CONST(2305843009213693952);
|
||||
CHECK_DEC_CONST(4611686018427387903);
|
||||
CHECK_DEC_CONST(4611686018427387904);
|
||||
CHECK_DEC_CONST(9223372036854775807);
|
||||
#if LLONG_AT_LEAST(65)
|
||||
CHECK_DEC_CONST(9223372036854775808);
|
||||
CHECK_DEC_CONST(18446744073709551615);
|
||||
#endif
|
||||
#if LLONG_AT_LEAST(66)
|
||||
CHECK_DEC_CONST(18446744073709551616);
|
||||
CHECK_DEC_CONST(36893488147419103231);
|
||||
#endif
|
||||
#if LLONG_AT_LEAST(67)
|
||||
CHECK_DEC_CONST(36893488147419103232);
|
||||
CHECK_DEC_CONST(73786976294838206463);
|
||||
#endif
|
||||
#if LLONG_AT_LEAST(68)
|
||||
CHECK_DEC_CONST(73786976294838206464);
|
||||
CHECK_DEC_CONST(147573952589676412927);
|
||||
#endif
|
||||
#if LLONG_AT_LEAST(69)
|
||||
CHECK_DEC_CONST(147573952589676412928);
|
||||
CHECK_DEC_CONST(295147905179352825855);
|
||||
#endif
|
||||
#if LLONG_AT_LEAST(70)
|
||||
CHECK_DEC_CONST(295147905179352825856);
|
||||
CHECK_DEC_CONST(590295810358705651711);
|
||||
#endif
|
||||
#if LLONG_AT_LEAST(71)
|
||||
CHECK_DEC_CONST(590295810358705651712);
|
||||
CHECK_DEC_CONST(1180591620717411303423);
|
||||
#endif
|
||||
#if LLONG_AT_LEAST(72)
|
||||
CHECK_DEC_CONST(1180591620717411303424);
|
||||
CHECK_DEC_CONST(2361183241434822606847);
|
||||
#endif
|
||||
/* Octal and hexadecimal. */
|
||||
/* Check all 2^n and 2^n - 1 up to 2^72 - 1. */
|
||||
CHECK_OCT_CONST(0);
|
||||
CHECK_HEX_CONST(0);
|
||||
CHECK_OCT_CONST(01);
|
||||
CHECK_HEX_CONST(1);
|
||||
CHECK_OCT_CONST(02);
|
||||
CHECK_HEX_CONST(2);
|
||||
CHECK_OCT_CONST(03);
|
||||
CHECK_HEX_CONST(3);
|
||||
CHECK_OCT_CONST(04);
|
||||
CHECK_HEX_CONST(4);
|
||||
CHECK_OCT_CONST(07);
|
||||
CHECK_HEX_CONST(7);
|
||||
CHECK_OCT_CONST(010);
|
||||
CHECK_HEX_CONST(8);
|
||||
CHECK_OCT_CONST(017);
|
||||
CHECK_HEX_CONST(f);
|
||||
CHECK_OCT_CONST(020);
|
||||
CHECK_HEX_CONST(10);
|
||||
CHECK_OCT_CONST(037);
|
||||
CHECK_HEX_CONST(1f);
|
||||
CHECK_OCT_CONST(040);
|
||||
CHECK_HEX_CONST(20);
|
||||
CHECK_OCT_CONST(077);
|
||||
CHECK_HEX_CONST(3f);
|
||||
CHECK_OCT_CONST(0100);
|
||||
CHECK_HEX_CONST(40);
|
||||
CHECK_OCT_CONST(0177);
|
||||
CHECK_HEX_CONST(7f);
|
||||
CHECK_OCT_CONST(0200);
|
||||
CHECK_HEX_CONST(80);
|
||||
CHECK_OCT_CONST(0377);
|
||||
CHECK_HEX_CONST(ff);
|
||||
CHECK_OCT_CONST(0400);
|
||||
CHECK_HEX_CONST(100);
|
||||
CHECK_OCT_CONST(0777);
|
||||
CHECK_HEX_CONST(1ff);
|
||||
CHECK_OCT_CONST(01000);
|
||||
CHECK_HEX_CONST(200);
|
||||
CHECK_OCT_CONST(01777);
|
||||
CHECK_HEX_CONST(3ff);
|
||||
CHECK_OCT_CONST(02000);
|
||||
CHECK_HEX_CONST(400);
|
||||
CHECK_OCT_CONST(03777);
|
||||
CHECK_HEX_CONST(7ff);
|
||||
CHECK_OCT_CONST(04000);
|
||||
CHECK_HEX_CONST(800);
|
||||
CHECK_OCT_CONST(07777);
|
||||
CHECK_HEX_CONST(fff);
|
||||
CHECK_OCT_CONST(010000);
|
||||
CHECK_HEX_CONST(1000);
|
||||
CHECK_OCT_CONST(017777);
|
||||
CHECK_HEX_CONST(1fff);
|
||||
CHECK_OCT_CONST(020000);
|
||||
CHECK_HEX_CONST(2000);
|
||||
CHECK_OCT_CONST(037777);
|
||||
CHECK_HEX_CONST(3fff);
|
||||
CHECK_OCT_CONST(040000);
|
||||
CHECK_HEX_CONST(4000);
|
||||
CHECK_OCT_CONST(077777);
|
||||
CHECK_HEX_CONST(7fff);
|
||||
CHECK_OCT_CONST(0100000);
|
||||
CHECK_HEX_CONST(8000);
|
||||
CHECK_OCT_CONST(0177777);
|
||||
CHECK_HEX_CONST(ffff);
|
||||
CHECK_OCT_CONST(0200000);
|
||||
CHECK_HEX_CONST(10000);
|
||||
CHECK_OCT_CONST(0377777);
|
||||
CHECK_HEX_CONST(1ffff);
|
||||
CHECK_OCT_CONST(0400000);
|
||||
CHECK_HEX_CONST(20000);
|
||||
CHECK_OCT_CONST(0777777);
|
||||
CHECK_HEX_CONST(3ffff);
|
||||
CHECK_OCT_CONST(01000000);
|
||||
CHECK_HEX_CONST(40000);
|
||||
CHECK_OCT_CONST(01777777);
|
||||
CHECK_HEX_CONST(7ffff);
|
||||
CHECK_OCT_CONST(02000000);
|
||||
CHECK_HEX_CONST(80000);
|
||||
CHECK_OCT_CONST(03777777);
|
||||
CHECK_HEX_CONST(fffff);
|
||||
CHECK_OCT_CONST(04000000);
|
||||
CHECK_HEX_CONST(100000);
|
||||
CHECK_OCT_CONST(07777777);
|
||||
CHECK_HEX_CONST(1fffff);
|
||||
CHECK_OCT_CONST(010000000);
|
||||
CHECK_HEX_CONST(200000);
|
||||
CHECK_OCT_CONST(017777777);
|
||||
CHECK_HEX_CONST(3fffff);
|
||||
CHECK_OCT_CONST(020000000);
|
||||
CHECK_HEX_CONST(400000);
|
||||
CHECK_OCT_CONST(037777777);
|
||||
CHECK_HEX_CONST(7fffff);
|
||||
CHECK_OCT_CONST(040000000);
|
||||
CHECK_HEX_CONST(800000);
|
||||
CHECK_OCT_CONST(077777777);
|
||||
CHECK_HEX_CONST(ffffff);
|
||||
CHECK_OCT_CONST(0100000000);
|
||||
CHECK_HEX_CONST(1000000);
|
||||
CHECK_OCT_CONST(0177777777);
|
||||
CHECK_HEX_CONST(1ffffff);
|
||||
CHECK_OCT_CONST(0200000000);
|
||||
CHECK_HEX_CONST(2000000);
|
||||
CHECK_OCT_CONST(0377777777);
|
||||
CHECK_HEX_CONST(3ffffff);
|
||||
CHECK_OCT_CONST(0400000000);
|
||||
CHECK_HEX_CONST(4000000);
|
||||
CHECK_OCT_CONST(0777777777);
|
||||
CHECK_HEX_CONST(7ffffff);
|
||||
CHECK_OCT_CONST(01000000000);
|
||||
CHECK_HEX_CONST(8000000);
|
||||
CHECK_OCT_CONST(01777777777);
|
||||
CHECK_HEX_CONST(fffffff);
|
||||
CHECK_OCT_CONST(02000000000);
|
||||
CHECK_HEX_CONST(10000000);
|
||||
CHECK_OCT_CONST(03777777777);
|
||||
CHECK_HEX_CONST(1fffffff);
|
||||
CHECK_OCT_CONST(04000000000);
|
||||
CHECK_HEX_CONST(20000000);
|
||||
CHECK_OCT_CONST(07777777777);
|
||||
CHECK_HEX_CONST(3fffffff);
|
||||
CHECK_OCT_CONST(010000000000);
|
||||
CHECK_HEX_CONST(40000000);
|
||||
CHECK_OCT_CONST(017777777777);
|
||||
CHECK_HEX_CONST(7fffffff);
|
||||
CHECK_OCT_CONST(020000000000);
|
||||
CHECK_HEX_CONST(80000000);
|
||||
CHECK_OCT_CONST(037777777777);
|
||||
CHECK_HEX_CONST(ffffffff);
|
||||
CHECK_OCT_CONST(040000000000);
|
||||
CHECK_HEX_CONST(100000000);
|
||||
CHECK_OCT_CONST(077777777777);
|
||||
CHECK_HEX_CONST(1ffffffff);
|
||||
CHECK_OCT_CONST(0100000000000);
|
||||
CHECK_HEX_CONST(200000000);
|
||||
CHECK_OCT_CONST(0177777777777);
|
||||
CHECK_HEX_CONST(3ffffffff);
|
||||
CHECK_OCT_CONST(0200000000000);
|
||||
CHECK_HEX_CONST(400000000);
|
||||
CHECK_OCT_CONST(0377777777777);
|
||||
CHECK_HEX_CONST(7ffffffff);
|
||||
CHECK_OCT_CONST(0400000000000);
|
||||
CHECK_HEX_CONST(800000000);
|
||||
CHECK_OCT_CONST(0777777777777);
|
||||
CHECK_HEX_CONST(fffffffff);
|
||||
CHECK_OCT_CONST(01000000000000);
|
||||
CHECK_HEX_CONST(1000000000);
|
||||
CHECK_OCT_CONST(01777777777777);
|
||||
CHECK_HEX_CONST(1fffffffff);
|
||||
CHECK_OCT_CONST(02000000000000);
|
||||
CHECK_HEX_CONST(2000000000);
|
||||
CHECK_OCT_CONST(03777777777777);
|
||||
CHECK_HEX_CONST(3fffffffff);
|
||||
CHECK_OCT_CONST(04000000000000);
|
||||
CHECK_HEX_CONST(4000000000);
|
||||
CHECK_OCT_CONST(07777777777777);
|
||||
CHECK_HEX_CONST(7fffffffff);
|
||||
CHECK_OCT_CONST(010000000000000);
|
||||
CHECK_HEX_CONST(8000000000);
|
||||
CHECK_OCT_CONST(017777777777777);
|
||||
CHECK_HEX_CONST(ffffffffff);
|
||||
CHECK_OCT_CONST(020000000000000);
|
||||
CHECK_HEX_CONST(10000000000);
|
||||
CHECK_OCT_CONST(037777777777777);
|
||||
CHECK_HEX_CONST(1ffffffffff);
|
||||
CHECK_OCT_CONST(040000000000000);
|
||||
CHECK_HEX_CONST(20000000000);
|
||||
CHECK_OCT_CONST(077777777777777);
|
||||
CHECK_HEX_CONST(3ffffffffff);
|
||||
CHECK_OCT_CONST(0100000000000000);
|
||||
CHECK_HEX_CONST(40000000000);
|
||||
CHECK_OCT_CONST(0177777777777777);
|
||||
CHECK_HEX_CONST(7ffffffffff);
|
||||
CHECK_OCT_CONST(0200000000000000);
|
||||
CHECK_HEX_CONST(80000000000);
|
||||
CHECK_OCT_CONST(0377777777777777);
|
||||
CHECK_HEX_CONST(fffffffffff);
|
||||
CHECK_OCT_CONST(0400000000000000);
|
||||
CHECK_HEX_CONST(100000000000);
|
||||
CHECK_OCT_CONST(0777777777777777);
|
||||
CHECK_HEX_CONST(1fffffffffff);
|
||||
CHECK_OCT_CONST(01000000000000000);
|
||||
CHECK_HEX_CONST(200000000000);
|
||||
CHECK_OCT_CONST(01777777777777777);
|
||||
CHECK_HEX_CONST(3fffffffffff);
|
||||
CHECK_OCT_CONST(02000000000000000);
|
||||
CHECK_HEX_CONST(400000000000);
|
||||
CHECK_OCT_CONST(03777777777777777);
|
||||
CHECK_HEX_CONST(7fffffffffff);
|
||||
CHECK_OCT_CONST(04000000000000000);
|
||||
CHECK_HEX_CONST(800000000000);
|
||||
CHECK_OCT_CONST(07777777777777777);
|
||||
CHECK_HEX_CONST(ffffffffffff);
|
||||
CHECK_OCT_CONST(010000000000000000);
|
||||
CHECK_HEX_CONST(1000000000000);
|
||||
CHECK_OCT_CONST(017777777777777777);
|
||||
CHECK_HEX_CONST(1ffffffffffff);
|
||||
CHECK_OCT_CONST(020000000000000000);
|
||||
CHECK_HEX_CONST(2000000000000);
|
||||
CHECK_OCT_CONST(037777777777777777);
|
||||
CHECK_HEX_CONST(3ffffffffffff);
|
||||
CHECK_OCT_CONST(040000000000000000);
|
||||
CHECK_HEX_CONST(4000000000000);
|
||||
CHECK_OCT_CONST(077777777777777777);
|
||||
CHECK_HEX_CONST(7ffffffffffff);
|
||||
CHECK_OCT_CONST(0100000000000000000);
|
||||
CHECK_HEX_CONST(8000000000000);
|
||||
CHECK_OCT_CONST(0177777777777777777);
|
||||
CHECK_HEX_CONST(fffffffffffff);
|
||||
CHECK_OCT_CONST(0200000000000000000);
|
||||
CHECK_HEX_CONST(10000000000000);
|
||||
CHECK_OCT_CONST(0377777777777777777);
|
||||
CHECK_HEX_CONST(1fffffffffffff);
|
||||
CHECK_OCT_CONST(0400000000000000000);
|
||||
CHECK_HEX_CONST(20000000000000);
|
||||
CHECK_OCT_CONST(0777777777777777777);
|
||||
CHECK_HEX_CONST(3fffffffffffff);
|
||||
CHECK_OCT_CONST(01000000000000000000);
|
||||
CHECK_HEX_CONST(40000000000000);
|
||||
CHECK_OCT_CONST(01777777777777777777);
|
||||
CHECK_HEX_CONST(7fffffffffffff);
|
||||
CHECK_OCT_CONST(02000000000000000000);
|
||||
CHECK_HEX_CONST(80000000000000);
|
||||
CHECK_OCT_CONST(03777777777777777777);
|
||||
CHECK_HEX_CONST(ffffffffffffff);
|
||||
CHECK_OCT_CONST(04000000000000000000);
|
||||
CHECK_HEX_CONST(100000000000000);
|
||||
CHECK_OCT_CONST(07777777777777777777);
|
||||
CHECK_HEX_CONST(1ffffffffffffff);
|
||||
CHECK_OCT_CONST(010000000000000000000);
|
||||
CHECK_HEX_CONST(200000000000000);
|
||||
CHECK_OCT_CONST(017777777777777777777);
|
||||
CHECK_HEX_CONST(3ffffffffffffff);
|
||||
CHECK_OCT_CONST(020000000000000000000);
|
||||
CHECK_HEX_CONST(400000000000000);
|
||||
CHECK_OCT_CONST(037777777777777777777);
|
||||
CHECK_HEX_CONST(7ffffffffffffff);
|
||||
CHECK_OCT_CONST(040000000000000000000);
|
||||
CHECK_HEX_CONST(800000000000000);
|
||||
CHECK_OCT_CONST(077777777777777777777);
|
||||
CHECK_HEX_CONST(fffffffffffffff);
|
||||
CHECK_OCT_CONST(0100000000000000000000);
|
||||
CHECK_HEX_CONST(1000000000000000);
|
||||
CHECK_OCT_CONST(0177777777777777777777);
|
||||
CHECK_HEX_CONST(1fffffffffffffff);
|
||||
CHECK_OCT_CONST(0200000000000000000000);
|
||||
CHECK_HEX_CONST(2000000000000000);
|
||||
CHECK_OCT_CONST(0377777777777777777777);
|
||||
CHECK_HEX_CONST(3fffffffffffffff);
|
||||
CHECK_OCT_CONST(0400000000000000000000);
|
||||
CHECK_HEX_CONST(4000000000000000);
|
||||
CHECK_OCT_CONST(0777777777777777777777);
|
||||
CHECK_HEX_CONST(7fffffffffffffff);
|
||||
CHECK_OCT_CONST(01000000000000000000000);
|
||||
CHECK_HEX_CONST(8000000000000000);
|
||||
CHECK_OCT_CONST(01777777777777777777777);
|
||||
CHECK_HEX_CONST(ffffffffffffffff);
|
||||
#if LLONG_AT_LEAST(65)
|
||||
CHECK_OCT_CONST(02000000000000000000000);
|
||||
CHECK_HEX_CONST(10000000000000000);
|
||||
CHECK_OCT_CONST(03777777777777777777777);
|
||||
CHECK_HEX_CONST(1ffffffffffffffff);
|
||||
#endif
|
||||
#if LLONG_AT_LEAST(66)
|
||||
CHECK_OCT_CONST(04000000000000000000000);
|
||||
CHECK_HEX_CONST(20000000000000000);
|
||||
CHECK_OCT_CONST(07777777777777777777777);
|
||||
CHECK_HEX_CONST(3ffffffffffffffff);
|
||||
#endif
|
||||
#if LLONG_AT_LEAST(67)
|
||||
CHECK_OCT_CONST(010000000000000000000000);
|
||||
CHECK_HEX_CONST(40000000000000000);
|
||||
CHECK_OCT_CONST(017777777777777777777777);
|
||||
CHECK_HEX_CONST(7ffffffffffffffff);
|
||||
#endif
|
||||
#if LLONG_AT_LEAST(68)
|
||||
CHECK_OCT_CONST(020000000000000000000000);
|
||||
CHECK_HEX_CONST(80000000000000000);
|
||||
CHECK_OCT_CONST(037777777777777777777777);
|
||||
CHECK_HEX_CONST(fffffffffffffffff);
|
||||
#endif
|
||||
#if LLONG_AT_LEAST(69)
|
||||
CHECK_OCT_CONST(040000000000000000000000);
|
||||
CHECK_HEX_CONST(100000000000000000);
|
||||
CHECK_OCT_CONST(077777777777777777777777);
|
||||
CHECK_HEX_CONST(1fffffffffffffffff);
|
||||
#endif
|
||||
#if LLONG_AT_LEAST(70)
|
||||
CHECK_OCT_CONST(0100000000000000000000000);
|
||||
CHECK_HEX_CONST(200000000000000000);
|
||||
CHECK_OCT_CONST(0177777777777777777777777);
|
||||
CHECK_HEX_CONST(3fffffffffffffffff);
|
||||
#endif
|
||||
#if LLONG_AT_LEAST(71)
|
||||
CHECK_OCT_CONST(0200000000000000000000000);
|
||||
CHECK_HEX_CONST(400000000000000000);
|
||||
CHECK_OCT_CONST(0377777777777777777777777);
|
||||
CHECK_HEX_CONST(7fffffffffffffffff);
|
||||
#endif
|
||||
#if LLONG_AT_LEAST(72)
|
||||
CHECK_OCT_CONST(0400000000000000000000000);
|
||||
CHECK_HEX_CONST(800000000000000000);
|
||||
CHECK_OCT_CONST(0777777777777777777777777);
|
||||
CHECK_HEX_CONST(ffffffffffffffffff);
|
||||
#endif
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
|
||||
#include <Carbon/Carbon.h>
|
||||
|
||||
//#import<vecLib/vecLib.h>
|
||||
@@ -1,5 +0,0 @@
|
||||
// clang -I/usr/include/c++/4.0.0 -I/usr/include/c++/4.0.0/powerpc-apple-darwin8 -I/usr/include/c++/4.0.0/backward INPUTS/iostream.cc -Eonly
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <stdint.h>
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
// This pounds on macro expansion for performance reasons. This is currently
|
||||
// heavily constrained by darwin's malloc.
|
||||
|
||||
// Function-like macros.
|
||||
#define A0(A, B) A B
|
||||
#define A1(A, B) A0(A,B) A0(A,B) A0(A,B) A0(A,B) A0(A,B) A0(A,B)
|
||||
#define A2(A, B) A1(A,B) A1(A,B) A1(A,B) A1(A,B) A1(A,B) A1(A,B)
|
||||
#define A3(A, B) A2(A,B) A2(A,B) A2(A,B) A2(A,B) A2(A,B) A2(A,B)
|
||||
#define A4(A, B) A3(A,B) A3(A,B) A3(A,B) A3(A,B) A3(A,B) A3(A,B)
|
||||
#define A5(A, B) A4(A,B) A4(A,B) A4(A,B) A4(A,B) A4(A,B) A4(A,B)
|
||||
#define A6(A, B) A5(A,B) A5(A,B) A5(A,B) A5(A,B) A5(A,B) A5(A,B)
|
||||
#define A7(A, B) A6(A,B) A6(A,B) A6(A,B) A6(A,B) A6(A,B) A6(A,B)
|
||||
#define A8(A, B) A7(A,B) A7(A,B) A7(A,B) A7(A,B) A7(A,B) A7(A,B)
|
||||
|
||||
A8(a, b)
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
|
||||
// This pounds on macro expansion for performance reasons. This is currently
|
||||
// heavily constrained by darwin's malloc.
|
||||
|
||||
// Object-like expansions
|
||||
#define A0 a b
|
||||
#define A1 A0 A0 A0 A0 A0 A0
|
||||
#define A2 A1 A1 A1 A1 A1 A1
|
||||
#define A3 A2 A2 A2 A2 A2 A2
|
||||
#define A4 A3 A3 A3 A3 A3 A3
|
||||
#define A5 A4 A4 A4 A4 A4 A4
|
||||
#define A6 A5 A5 A5 A5 A5 A5
|
||||
#define A7 A6 A6 A6 A6 A6 A6
|
||||
#define A8 A7 A7 A7 A7 A7 A7
|
||||
|
||||
A8
|
||||
@@ -1,47 +0,0 @@
|
||||
#define __extension__
|
||||
|
||||
#define __stpcpy(dest, src) (__extension__ (__builtin_constant_p (src) ? (__string2_1bptr_p (src) && strlen (src) + 1 <= 8 ? __stpcpy_small (dest, __stpcpy_args (src), strlen (src) + 1) : ((char *) __mempcpy (dest, src, strlen (src) + 1) - 1)) : __stpcpy (dest, src)))
|
||||
#define stpcpy(dest, src) __stpcpy (dest, src)
|
||||
#define __stpcpy_args(src) __extension__ __STRING2_SMALL_GET16 (src, 0), __extension__ __STRING2_SMALL_GET16 (src, 4), __extension__ __STRING2_SMALL_GET32 (src, 0), __extension__ __STRING2_SMALL_GET32 (src, 4)
|
||||
|
||||
#define __mempcpy(dest, src, n) (__extension__ (__builtin_constant_p (src) && __builtin_constant_p (n) && __string2_1bptr_p (src) && n <= 8 ? __mempcpy_small (dest, __mempcpy_args (src), n) : __mempcpy (dest, src, n)))
|
||||
#define mempcpy(dest, src, n) __mempcpy (dest, src, n)
|
||||
#define __mempcpy_args(src) ((char *) (src))[0], ((char *) (src))[2], ((char *) (src))[4], ((char *) (src))[6], __extension__ __STRING2_SMALL_GET16 (src, 0), __extension__ __STRING2_SMALL_GET16 (src, 4), __extension__ __STRING2_SMALL_GET32 (src, 0), __extension__ __STRING2_SMALL_GET32 (src, 4)
|
||||
|
||||
#define __STRING2_SMALL_GET16(src, idx) (((__const unsigned char *) (__const char *) (src))[idx + 1] << 8 | ((__const unsigned char *) (__const char *) (src))[idx])
|
||||
|
||||
#define __STRING2_SMALL_GET32(src, idx) (((((__const unsigned char *) (__const char *) (src))[idx + 3] << 8 | ((__const unsigned char *) (__const char *) (src))[idx + 2]) << 8 | ((__const unsigned char *) (__const char *) (src))[idx + 1]) << 8 | ((__const unsigned char *) (__const char *) (src))[idx])
|
||||
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (a, b), c), d), e)
|
||||
@@ -1,63 +0,0 @@
|
||||
==============================================================================
|
||||
LLVM Release License
|
||||
==============================================================================
|
||||
University of Illinois/NCSA
|
||||
Open Source License
|
||||
|
||||
Copyright (c) 2007 University of Illinois at Urbana-Champaign.
|
||||
All rights reserved.
|
||||
|
||||
Developed by:
|
||||
|
||||
LLVM Team
|
||||
|
||||
University of Illinois at Urbana-Champaign
|
||||
|
||||
http://llvm.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal with
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimers.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimers in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of the LLVM Team, University of Illinois at
|
||||
Urbana-Champaign, nor the names of its contributors may be used to
|
||||
endorse or promote products derived from this Software without specific
|
||||
prior written permission.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
|
||||
SOFTWARE.
|
||||
|
||||
==============================================================================
|
||||
The LLVM software contains code written by third parties. Such software will
|
||||
have its own individual LICENSE.TXT file in the directory in which it appears.
|
||||
This file will describe the copyrights, license, and restrictions which apply
|
||||
to that code.
|
||||
|
||||
The disclaimer of warranty in the University of Illinois Open Source License
|
||||
applies to all code in the LLVM Distribution, and nothing in any of the
|
||||
other licenses gives permission to use the names of the LLVM Team or the
|
||||
University of Illinois to endorse or promote products derived from this
|
||||
Software.
|
||||
|
||||
The following pieces of software have additional or alternate copyrights,
|
||||
licenses, and/or restrictions:
|
||||
|
||||
Program Directory
|
||||
------- ---------
|
||||
<none yet>
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
LEVEL = ../..
|
||||
DIRS := lib Driver docs tools
|
||||
|
||||
include $(LEVEL)/Makefile.common
|
||||
|
||||
ifneq ($(PROJ_SRC_ROOT),$(PROJ_OBJ_ROOT))
|
||||
test::
|
||||
$(Verb) if [ ! -f test/Makefile ]; then \
|
||||
$(MKDIR) test; \
|
||||
$(CP) $(PROJ_SRC_DIR)/test/Makefile test/Makefile; \
|
||||
fi
|
||||
endif
|
||||
|
||||
test::
|
||||
@ $(MAKE) -C test
|
||||
|
||||
report::
|
||||
@ $(MAKE) -C test report
|
||||
|
||||
clean::
|
||||
@ $(MAKE) -C test clean
|
||||
|
||||
.PHONY: test report clean
|
||||
@@ -1,5 +0,0 @@
|
||||
# This file provides information for llvm-top
|
||||
DepModule: llvm
|
||||
ConfigCmd:
|
||||
ConfigTest:
|
||||
BuildCmd:
|
||||
135
clang/NOTES.txt
135
clang/NOTES.txt
@@ -1,135 +0,0 @@
|
||||
//===---------------------------------------------------------------------===//
|
||||
// Random Notes
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
C90/C99/C++ Comparisons:
|
||||
http://david.tribble.com/text/cdiffs.htm
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
To time GCC preprocessing speed without output, use:
|
||||
"time gcc -MM file"
|
||||
This is similar to -Eonly.
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
Creating and using a PTH file for performance measurement (use a release-asserts
|
||||
build).
|
||||
|
||||
$ clang -x objective-c-header INPUTS/Cocoa_h.m -o /tmp/tokencache
|
||||
$ clang -token-cache /tmp/tokencache INPUTS/Cocoa_h.m
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
C++ Template Instantiation benchmark:
|
||||
http://users.rcn.com/abrahams/instantiation_speed/index.html
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
TODO: File Manager Speedup:
|
||||
|
||||
We currently do a lot of stat'ing for files that don't exist, particularly
|
||||
when lots of -I paths exist (e.g. see the <iostream> example, check for
|
||||
failures in stat in FileManager::getFile). It would be far better to make
|
||||
the following changes:
|
||||
1. FileEntry contains a sys::Path instead of a std::string for Name.
|
||||
2. sys::Path contains timestamp and size, lazily computed. Eliminate from
|
||||
FileEntry.
|
||||
3. File UIDs are created on request, not when files are opened.
|
||||
These changes make it possible to efficiently have FileEntry objects for
|
||||
files that exist on the file system, but have not been used yet.
|
||||
|
||||
Once this is done:
|
||||
1. DirectoryEntry gets a boolean value "has read entries". When false, not
|
||||
all entries in the directory are in the file mgr, when true, they are.
|
||||
2. Instead of stat'ing the file in FileManager::getFile, check to see if
|
||||
the dir has been read. If so, fail immediately, if not, read the dir,
|
||||
then retry.
|
||||
3. Reading the dir uses the getdirentries syscall, creating an FileEntry
|
||||
for all files found.
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
TODO: Fast #Import:
|
||||
|
||||
* Get frameworks that don't use #import to do so, e.g.
|
||||
DirectoryService, AudioToolbox, CoreFoundation, etc. Why not using #import?
|
||||
Because they work in C mode? C has #import.
|
||||
* Have the lexer return a token for #import instead of handling it itself.
|
||||
- Create a new preprocessor object with no external state (no -D/U options
|
||||
from the command line, etc). Alternatively, keep track of exactly which
|
||||
external state is used by a #import: declare it somehow.
|
||||
* When having reading a #import file, keep track of whether we have (and/or
|
||||
which) seen any "configuration" macros. Various cases:
|
||||
- Uses of target args (__POWERPC__, __i386): Header has to be parsed
|
||||
multiple times, per-target. What about #ifndef checks? How do we know?
|
||||
- "Configuration" preprocessor macros not defined: POWERPC, etc. What about
|
||||
things like __STDC__ etc? What is and what isn't allowed.
|
||||
* Special handling for "umbrella" headers, which just contain #import stmts:
|
||||
- Cocoa.h/AppKit.h - Contain pointers to digests instead of entire digests
|
||||
themselves? Foundation.h isn't pure umbrella!
|
||||
* Frameworks digests:
|
||||
- Can put "digest" of a framework-worth of headers into the framework
|
||||
itself. To open AppKit, just mmap
|
||||
/System/Library/Frameworks/AppKit.framework/"digest", which provides a
|
||||
symbol table in a well defined format. Lazily unstream stuff that is
|
||||
needed. Contains declarations, macros, and debug information.
|
||||
- System frameworks ship with digests. How do we handle configuration
|
||||
information? How do we handle stuff like:
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_2
|
||||
which guards a bunch of decls? Should there be a couple of default
|
||||
configs, then have the UI fall back to building/caching its own?
|
||||
- GUI automatically builds digests when UI is idle, both of system
|
||||
frameworks if they aren't not available in the right config, and of app
|
||||
frameworks.
|
||||
- GUI builds dependence graph of frameworks/digests based on #imports. If a
|
||||
digest is out date, dependent digests are automatically invalidated.
|
||||
|
||||
* New constraints on #import for objc-v3:
|
||||
- #imported file must not define non-inline function bodies.
|
||||
- Alternatively, they can, and these bodies get compiled/linked *once*
|
||||
per app into a dylib. What about building user dylibs?
|
||||
- Restrictions on ObjC grammar: can't #import the body of a for stmt or fn.
|
||||
- Compiler must detect and reject these cases.
|
||||
- #defines defined within a #import have two behaviors:
|
||||
- By default, they escape the header. These macros *cannot* be #undef'd
|
||||
by other code: this is enforced by the front-end.
|
||||
- Optionally, user can specify what macros escape (whitelist) or can use
|
||||
#undef.
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
// Specifying targets: -triple and -arch
|
||||
===---------------------------------------------------------------------===//
|
||||
|
||||
The clang supports "-triple" and "-arch" options. At most one -triple and one
|
||||
-arch option may be specified. Both are optional.
|
||||
|
||||
The "selection of target" behavior is defined as follows:
|
||||
|
||||
(1) If the user does not specify -triple, we default to the host triple.
|
||||
(2) If the user specifies a -arch, that overrides the arch in the host or
|
||||
specified triple.
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
|
||||
verifyInputConstraint and verifyOutputConstraint should not return bool.
|
||||
|
||||
Instead we should return something like:
|
||||
|
||||
enum VerifyConstraintResult {
|
||||
Valid,
|
||||
|
||||
// Output only
|
||||
OutputOperandConstraintLacksEqualsCharacter,
|
||||
MatchingConstraintNotValidInOutputOperand,
|
||||
|
||||
// Input only
|
||||
InputOperandConstraintContainsEqualsCharacter,
|
||||
MatchingConstraintReferencesInvalidOperandNumber,
|
||||
|
||||
// Both
|
||||
PercentConstraintUsedWithLastOperand
|
||||
};
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
198
clang/README.txt
198
clang/README.txt
@@ -1,198 +0,0 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
// C Language Family Front-end
|
||||
//===----------------------------------------------------------------------===//
|
||||
Chris Lattner
|
||||
|
||||
I. Introduction:
|
||||
|
||||
clang: noun
|
||||
1. A loud, resonant, metallic sound.
|
||||
2. The strident call of a crane or goose.
|
||||
3. C-language family front-end toolkit.
|
||||
|
||||
The world needs better compiler tools, tools which are built as libraries. This
|
||||
design point allows reuse of the tools in new and novel ways. However, building
|
||||
the tools as libraries isn't enough: they must have clean APIs, be as
|
||||
decoupled from each other as possible, and be easy to modify/extend. This
|
||||
requires clean layering, decent design, and avoiding tying the libraries to a
|
||||
specific use. Oh yeah, did I mention that we want the resultant libraries to
|
||||
be as fast as possible? :)
|
||||
|
||||
This front-end is built as a component of the LLVM toolkit that can be used
|
||||
with the LLVM backend or independently of it. In this spirit, the API has been
|
||||
carefully designed as the following components:
|
||||
|
||||
libsupport - Basic support library, reused from LLVM.
|
||||
|
||||
libsystem - System abstraction library, reused from LLVM.
|
||||
|
||||
libbasic - Diagnostics, SourceLocations, SourceBuffer abstraction,
|
||||
file system caching for input source files. This depends on
|
||||
libsupport and libsystem.
|
||||
|
||||
libast - Provides classes to represent the C AST, the C type system,
|
||||
builtin functions, and various helpers for analyzing and
|
||||
manipulating the AST (visitors, pretty printers, etc). This
|
||||
library depends on libbasic.
|
||||
|
||||
|
||||
liblex - C/C++/ObjC lexing and preprocessing, identifier hash table,
|
||||
pragma handling, tokens, and macros. This depends on libbasic.
|
||||
|
||||
libparse - C (for now) parsing and local semantic analysis. This library
|
||||
invokes coarse-grained 'Actions' provided by the client to do
|
||||
stuff (e.g. libsema builds ASTs). This depends on liblex.
|
||||
|
||||
libsema - Provides a set of parser actions to build a standardized AST
|
||||
for programs. AST's are 'streamed' out a top-level declaration
|
||||
at a time, allowing clients to use decl-at-a-time processing,
|
||||
build up entire translation units, or even build 'whole
|
||||
program' ASTs depending on how they use the APIs. This depends
|
||||
on libast and libparse.
|
||||
|
||||
librewrite - Fast, scalable rewriting of source code. This operates on
|
||||
the raw syntactic text of source code, allowing a client
|
||||
to insert and delete text in very large source files using
|
||||
the same source location information embedded in ASTs. This
|
||||
is intended to be a low-level API that is useful for
|
||||
higher-level clients and libraries such as code refactoring.
|
||||
|
||||
libanalysis - Source-level dataflow analysis useful for performing analyses
|
||||
such as computing live variables. It also includes a
|
||||
path-sensitive "graph-reachability" engine for writing
|
||||
analyses that reason about different possible paths of
|
||||
execution through source code. This is currently being
|
||||
employed to write a set of checks for finding bugs in software.
|
||||
|
||||
libcodegen - Lower the AST to LLVM IR for optimization & codegen. Depends
|
||||
on libast.
|
||||
|
||||
clang - An example driver, client of the libraries at various levels.
|
||||
This depends on all these libraries, and on LLVM VMCore.
|
||||
|
||||
This front-end has been intentionally built as a DAG of libraries, making it
|
||||
easy to reuse individual parts or replace pieces if desired. For example, to
|
||||
build a preprocessor, you take the Basic and Lexer libraries. If you want an
|
||||
indexer, you take those plus the Parser library and provide some actions for
|
||||
indexing. If you want a refactoring, static analysis, or source-to-source
|
||||
compiler tool, it makes sense to take those plus the AST building and semantic
|
||||
analyzer library. Finally, if you want to use this with the LLVM backend,
|
||||
you'd take these components plus the AST to LLVM lowering code.
|
||||
|
||||
In the future I hope this toolkit will grow to include new and interesting
|
||||
components, including a C++ front-end, ObjC support, and a whole lot of other
|
||||
things.
|
||||
|
||||
Finally, it should be pointed out that the goal here is to build something that
|
||||
is high-quality and industrial-strength: all the obnoxious features of the C
|
||||
family must be correctly supported (trigraphs, preprocessor arcana, K&R-style
|
||||
prototypes, GCC/MS extensions, etc). It cannot be used if it is not 'real'.
|
||||
|
||||
|
||||
II. Usage of clang driver:
|
||||
|
||||
* Basic Command-Line Options:
|
||||
- Help: clang --help
|
||||
- Standard GCC options accepted: -E, -I*, -i*, -pedantic, -std=c90, etc.
|
||||
- To make diagnostics more gcc-like: -fno-caret-diagnostics -fno-show-column
|
||||
- Enable metric printing: -stats
|
||||
|
||||
* -fsyntax-only is currently the default mode.
|
||||
|
||||
* -E mode works the same way as GCC.
|
||||
|
||||
* -Eonly mode does all preprocessing, but does not print the output,
|
||||
useful for timing the preprocessor.
|
||||
|
||||
* -fsyntax-only is currently partially implemented, lacking some
|
||||
semantic analysis (some errors and warnings are not produced).
|
||||
|
||||
* -parse-noop parses code without building an AST. This is useful
|
||||
for timing the cost of the parser without including AST building
|
||||
time.
|
||||
|
||||
* -parse-ast builds ASTs, but doesn't print them. This is most
|
||||
useful for timing AST building vs -parse-noop.
|
||||
|
||||
* -parse-ast-print pretty prints most expression and statements nodes.
|
||||
|
||||
* -parse-ast-check checks that diagnostic messages that are expected
|
||||
are reported and that those which are reported are expected.
|
||||
|
||||
* -dump-cfg builds ASTs and then CFGs. CFGs are then pretty-printed.
|
||||
|
||||
* -view-cfg builds ASTs and then CFGs. CFGs are then visualized by
|
||||
invoking Graphviz.
|
||||
|
||||
For more information on getting Graphviz to work with clang/LLVM,
|
||||
see: http://llvm.org/docs/ProgrammersManual.html#ViewGraph
|
||||
|
||||
|
||||
III. Current advantages over GCC:
|
||||
|
||||
* Column numbers are fully tracked (no 256 col limit, no GCC-style pruning).
|
||||
* All diagnostics have column numbers, includes 'caret diagnostics', and they
|
||||
highlight regions of interesting code (e.g. the LHS and RHS of a binop).
|
||||
* Full diagnostic customization by client (can format diagnostics however they
|
||||
like, e.g. in an IDE or refactoring tool) through DiagnosticClient interface.
|
||||
* Built as a framework, can be reused by multiple tools.
|
||||
* All languages supported linked into same library (no cc1,cc1obj, ...).
|
||||
* mmap's code in read-only, does not dirty the pages like GCC (mem footprint).
|
||||
* LLVM License, can be linked into non-GPL projects.
|
||||
* Full diagnostic control, per diagnostic. Diagnostics are identified by ID.
|
||||
* Significantly faster than GCC at semantic analysis, parsing, preprocessing
|
||||
and lexing.
|
||||
* Defers exposing platform-specific stuff to as late as possible, tracks use of
|
||||
platform-specific features (e.g. #ifdef PPC) to allow 'portable bytecodes'.
|
||||
* The lexer doesn't rely on the "lexer hack": it has no notion of scope and
|
||||
does not categorize identifiers as types or variables -- this is up to the
|
||||
parser to decide.
|
||||
|
||||
Potential Future Features:
|
||||
|
||||
* Fine grained diag control within the source (#pragma enable/disable warning).
|
||||
* Better token tracking within macros? (Token came from this line, which is
|
||||
a macro argument instantiated here, recursively instantiated here).
|
||||
* Fast #import with a module system.
|
||||
* Dependency tracking: change to header file doesn't recompile every function
|
||||
that texually depends on it: recompile only those functions that need it.
|
||||
This is aka 'incremental parsing'.
|
||||
|
||||
|
||||
IV. Missing Functionality / Improvements
|
||||
|
||||
clang driver:
|
||||
* Include search paths are hard-coded into the driver. Doh.
|
||||
|
||||
File Manager:
|
||||
* Reduce syscalls for reduced compile time, see NOTES.txt.
|
||||
|
||||
Lexer:
|
||||
* Source character mapping. GCC supports ASCII and UTF-8.
|
||||
See GCC options: -ftarget-charset and -ftarget-wide-charset.
|
||||
* Universal character support. Experimental in GCC, enabled with
|
||||
-fextended-identifiers.
|
||||
* -fpreprocessed mode.
|
||||
|
||||
Preprocessor:
|
||||
* Know about apple header maps.
|
||||
* #assert/#unassert
|
||||
* #line / #file directives (currently accepted and ignored).
|
||||
* MSExtension: "L#param" stringizes to a wide string literal.
|
||||
* Charize extension: "#define F(o) #@o F(a)" -> 'a'.
|
||||
* Consider merging the parser's expression parser into the preprocessor to
|
||||
eliminate duplicate code.
|
||||
* Add support for -M*
|
||||
|
||||
Traditional Preprocessor:
|
||||
* Currently, we have none. :)
|
||||
|
||||
Parser:
|
||||
* C90/K&R modes are only partially implemented.
|
||||
* __extension__ is currently just skipped and ignored.
|
||||
|
||||
Semantic Analysis:
|
||||
* Perhaps 85% done.
|
||||
|
||||
LLVM Code Gen:
|
||||
* Most of the easy stuff is done, probably 65.42% done so far.
|
||||
@@ -1,55 +0,0 @@
|
||||
//===---------------------------------------------------------------------===//
|
||||
// Minor random things that can be improved
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
|
||||
Warn about "X && 0x1000" saying that the user may mean "X & 0x1000".
|
||||
We should do this for any immediate except zero, so long as it doesn't come
|
||||
from a macro expansion. Likewise for ||.
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
Lexer-related diagnostics should point to the problematic character, not the
|
||||
start of the token. For example:
|
||||
|
||||
int y = 0000\
|
||||
00080;
|
||||
|
||||
diag.c:4:9: error: invalid digit '8' in octal constant
|
||||
int y = 0000\
|
||||
^
|
||||
|
||||
should be:
|
||||
|
||||
diag.c:4:9: error: invalid digit '8' in octal constant
|
||||
00080;
|
||||
^
|
||||
|
||||
This specific diagnostic is implemented, but others should be updated.
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
C++ (checker): For iterators, warn of the use of "iterator++" instead
|
||||
of "++iterator" when when the value returned by operator++(int) is
|
||||
ignored.
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
We want to keep more source range information in Declarator to help
|
||||
produce better diagnostics. Declarator::getSourceRange() should be
|
||||
implemented to give a range for the whole declarator with all of its
|
||||
specifiers, and DeclaratorChunk::ParamInfo should also have a source
|
||||
range covering the whole parameter, so that an error message like this:
|
||||
|
||||
overloaded-operator-decl.cpp:37:23: error: parameter of overloaded post-increment operator must have type 'int' (not 'float')
|
||||
X operator++(X&, const float& f);
|
||||
^
|
||||
can be turned into something like this:
|
||||
|
||||
overloaded-operator-decl.cpp:37:23: error: parameter of overloaded post-increment operator must have type 'int' (not 'float')
|
||||
X operator++(X&, const float& f);
|
||||
^ ~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,94 +0,0 @@
|
||||
##===- docs/Makefile ---------------------------------------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
|
||||
LEVEL := ../../..
|
||||
DIRS :=
|
||||
|
||||
ifdef BUILD_FOR_WEBSITE
|
||||
PROJ_OBJ_DIR = .
|
||||
DOXYGEN = doxygen
|
||||
|
||||
$(PROJ_OBJ_DIR)/doxygen.cfg: doxygen.cfg.in
|
||||
cat $< | sed \
|
||||
-e 's/@abs_top_srcdir@/../g' \
|
||||
-e 's/@DOT@/dot/g' \
|
||||
-e 's/@PACKAGE_VERSION@/mainline/' \
|
||||
-e 's/@abs_top_builddir@/../g' > $@
|
||||
endif
|
||||
|
||||
include $(LEVEL)/Makefile.common
|
||||
|
||||
HTML := $(wildcard $(PROJ_SRC_DIR)/*.html) \
|
||||
$(wildcard $(PROJ_SRC_DIR)/*.css)
|
||||
#IMAGES := $(wildcard $(PROJ_SRC_DIR)/img/*.*)
|
||||
DOXYFILES := doxygen.cfg.in doxygen.css doxygen.footer doxygen.header \
|
||||
doxygen.intro
|
||||
EXTRA_DIST := $(HTML) $(DOXYFILES) llvm.css CommandGuide img
|
||||
|
||||
.PHONY: install-html install-doxygen doxygen generated
|
||||
|
||||
install_targets := install-html
|
||||
ifeq ($(ENABLE_DOXYGEN),1)
|
||||
install_targets += install-doxygen
|
||||
endif
|
||||
install-local:: $(install_targets)
|
||||
|
||||
# Live documentation is generated for the web site using this target:
|
||||
# 'make generated BUILD_FOR_WEBSITE=1'
|
||||
generated:: doxygen
|
||||
|
||||
install-html: $(PROJ_OBJ_DIR)/html.tar.gz
|
||||
$(Echo) Installing HTML documentation
|
||||
$(Verb) $(MKDIR) $(PROJ_docsdir)/html
|
||||
$(Verb) $(MKDIR) $(PROJ_docsdir)/html/img
|
||||
$(Verb) $(DataInstall) $(HTML) $(PROJ_docsdir)/html
|
||||
# $(Verb) $(DataInstall) $(IMAGES) $(PROJ_docsdir)/html/img
|
||||
$(Verb) $(DataInstall) $(PROJ_OBJ_DIR)/html.tar.gz $(PROJ_docsdir)
|
||||
|
||||
$(PROJ_OBJ_DIR)/html.tar.gz: $(HTML)
|
||||
$(Echo) Packaging HTML documentation
|
||||
$(Verb) $(RM) -rf $@ $(PROJ_OBJ_DIR)/html.tar
|
||||
$(Verb) cd $(PROJ_SRC_DIR) && \
|
||||
$(TAR) cf $(PROJ_OBJ_DIR)/html.tar *.html
|
||||
$(Verb) $(GZIP) $(PROJ_OBJ_DIR)/html.tar
|
||||
|
||||
install-doxygen: doxygen
|
||||
$(Echo) Installing doxygen documentation
|
||||
$(Verb) $(MKDIR) $(PROJ_docsdir)/html/doxygen
|
||||
$(Verb) $(DataInstall) $(PROJ_OBJ_DIR)/doxygen.tar.gz $(PROJ_docsdir)
|
||||
$(Verb) cd $(PROJ_OBJ_DIR)/doxygen && \
|
||||
$(FIND) . -type f -exec \
|
||||
$(DataInstall) {} $(PROJ_docsdir)/html/doxygen \;
|
||||
|
||||
doxygen: regendoc $(PROJ_OBJ_DIR)/doxygen.tar.gz
|
||||
|
||||
regendoc:
|
||||
$(Echo) Building doxygen documentation
|
||||
$(Verb) if test -e $(PROJ_OBJ_DIR)/doxygen ; then \
|
||||
$(RM) -rf $(PROJ_OBJ_DIR)/doxygen ; \
|
||||
fi
|
||||
$(Verb) $(DOXYGEN) $(PROJ_OBJ_DIR)/doxygen.cfg
|
||||
|
||||
$(PROJ_OBJ_DIR)/doxygen.tar.gz: $(DOXYFILES) $(PROJ_OBJ_DIR)/doxygen.cfg
|
||||
$(Echo) Packaging doxygen documentation
|
||||
$(Verb) $(RM) -rf $@ $(PROJ_OBJ_DIR)/doxygen.tar
|
||||
$(Verb) $(TAR) cf $(PROJ_OBJ_DIR)/doxygen.tar doxygen
|
||||
$(Verb) $(GZIP) $(PROJ_OBJ_DIR)/doxygen.tar
|
||||
$(Verb) $(CP) $(PROJ_OBJ_DIR)/doxygen.tar.gz $(PROJ_OBJ_DIR)/doxygen/html/
|
||||
|
||||
userloc: $(LLVM_SRC_ROOT)/docs/userloc.html
|
||||
|
||||
$(LLVM_SRC_ROOT)/docs/userloc.html:
|
||||
$(Echo) Making User LOC Table
|
||||
$(Verb) cd $(LLVM_SRC_ROOT) ; ./utils/userloc.pl -details -recurse \
|
||||
-html lib include tools runtime utils examples autoconf test > docs/userloc.html
|
||||
|
||||
uninstall-local::
|
||||
$(Echo) Uninstalling Documentation
|
||||
$(Verb) $(RM) -rf $(PROJ_docsdir)
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,378 +0,0 @@
|
||||
BODY,H1,H2,H3,H4,H5,H6,P,CENTER,TD,TH,UL,DL,DIV {
|
||||
font-family: Verdana,Geneva,Arial,Helvetica,sans-serif;
|
||||
}
|
||||
BODY,TD {
|
||||
font-size: 90%;
|
||||
}
|
||||
H1 {
|
||||
text-align: center;
|
||||
font-size: 140%;
|
||||
font-weight: bold;
|
||||
}
|
||||
H2 {
|
||||
font-size: 120%;
|
||||
font-style: italic;
|
||||
}
|
||||
H3 {
|
||||
font-size: 100%;
|
||||
}
|
||||
CAPTION { font-weight: bold }
|
||||
DIV.qindex {
|
||||
width: 100%;
|
||||
background-color: #eeeeff;
|
||||
border: 1px solid #b0b0b0;
|
||||
text-align: center;
|
||||
margin: 2px;
|
||||
padding: 2px;
|
||||
line-height: 140%;
|
||||
}
|
||||
DIV.nav {
|
||||
width: 100%;
|
||||
background-color: #eeeeff;
|
||||
border: 1px solid #b0b0b0;
|
||||
text-align: center;
|
||||
margin: 2px;
|
||||
padding: 2px;
|
||||
line-height: 140%;
|
||||
}
|
||||
DIV.navtab {
|
||||
background-color: #eeeeff;
|
||||
border: 1px solid #b0b0b0;
|
||||
text-align: center;
|
||||
margin: 2px;
|
||||
margin-right: 15px;
|
||||
padding: 2px;
|
||||
}
|
||||
TD.navtab {
|
||||
font-size: 70%;
|
||||
}
|
||||
A.qindex {
|
||||
text-decoration: none;
|
||||
font-weight: bold;
|
||||
color: #1A419D;
|
||||
}
|
||||
A.qindex:visited {
|
||||
text-decoration: none;
|
||||
font-weight: bold;
|
||||
color: #1A419D
|
||||
}
|
||||
A.qindex:hover {
|
||||
text-decoration: none;
|
||||
background-color: #ddddff;
|
||||
}
|
||||
A.qindexHL {
|
||||
text-decoration: none;
|
||||
font-weight: bold;
|
||||
background-color: #6666cc;
|
||||
color: #ffffff;
|
||||
border: 1px double #9295C2;
|
||||
}
|
||||
A.qindexHL:hover {
|
||||
text-decoration: none;
|
||||
background-color: #6666cc;
|
||||
color: #ffffff;
|
||||
}
|
||||
A.qindexHL:visited {
|
||||
text-decoration: none; background-color: #6666cc; color: #ffffff }
|
||||
A.el { text-decoration: none; font-weight: bold }
|
||||
A.elRef { font-weight: bold }
|
||||
A.code:link { text-decoration: none; font-weight: normal; color: #0000FF}
|
||||
A.code:visited { text-decoration: none; font-weight: normal; color: #0000FF}
|
||||
A.codeRef:link { font-weight: normal; color: #0000FF}
|
||||
A.codeRef:visited { font-weight: normal; color: #0000FF}
|
||||
A:hover { text-decoration: none; background-color: #f2f2ff }
|
||||
DL.el { margin-left: -1cm }
|
||||
.fragment {
|
||||
font-family: Fixed, monospace;
|
||||
font-size: 95%;
|
||||
}
|
||||
PRE.fragment {
|
||||
border: 1px solid #CCCCCC;
|
||||
background-color: #f5f5f5;
|
||||
margin-top: 4px;
|
||||
margin-bottom: 4px;
|
||||
margin-left: 2px;
|
||||
margin-right: 8px;
|
||||
padding-left: 6px;
|
||||
padding-right: 6px;
|
||||
padding-top: 4px;
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
DIV.ah { background-color: black; font-weight: bold; color: #ffffff; margin-bottom: 3px; margin-top: 3px }
|
||||
TD.md { background-color: #F4F4FB; font-weight: bold; }
|
||||
TD.mdPrefix {
|
||||
background-color: #F4F4FB;
|
||||
color: #606060;
|
||||
font-size: 80%;
|
||||
}
|
||||
TD.mdname1 { background-color: #F4F4FB; font-weight: bold; color: #602020; }
|
||||
TD.mdname { background-color: #F4F4FB; font-weight: bold; color: #602020; width: 600px; }
|
||||
DIV.groupHeader {
|
||||
margin-left: 16px;
|
||||
margin-top: 12px;
|
||||
margin-bottom: 6px;
|
||||
font-weight: bold;
|
||||
}
|
||||
DIV.groupText { margin-left: 16px; font-style: italic; font-size: 90% }
|
||||
BODY {
|
||||
background: white;
|
||||
color: black;
|
||||
margin-right: 20px;
|
||||
margin-left: 20px;
|
||||
}
|
||||
TD.indexkey {
|
||||
background-color: #eeeeff;
|
||||
font-weight: bold;
|
||||
padding-right : 10px;
|
||||
padding-top : 2px;
|
||||
padding-left : 10px;
|
||||
padding-bottom : 2px;
|
||||
margin-left : 0px;
|
||||
margin-right : 0px;
|
||||
margin-top : 2px;
|
||||
margin-bottom : 2px;
|
||||
border: 1px solid #CCCCCC;
|
||||
}
|
||||
TD.indexvalue {
|
||||
background-color: #eeeeff;
|
||||
font-style: italic;
|
||||
padding-right : 10px;
|
||||
padding-top : 2px;
|
||||
padding-left : 10px;
|
||||
padding-bottom : 2px;
|
||||
margin-left : 0px;
|
||||
margin-right : 0px;
|
||||
margin-top : 2px;
|
||||
margin-bottom : 2px;
|
||||
border: 1px solid #CCCCCC;
|
||||
}
|
||||
TR.memlist {
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
P.formulaDsp { text-align: center; }
|
||||
IMG.formulaDsp { }
|
||||
IMG.formulaInl { vertical-align: middle; }
|
||||
SPAN.keyword { color: #008000 }
|
||||
SPAN.keywordtype { color: #604020 }
|
||||
SPAN.keywordflow { color: #e08000 }
|
||||
SPAN.comment { color: #800000 }
|
||||
SPAN.preprocessor { color: #806020 }
|
||||
SPAN.stringliteral { color: #002080 }
|
||||
SPAN.charliteral { color: #008080 }
|
||||
.mdTable {
|
||||
border: 1px solid #868686;
|
||||
background-color: #F4F4FB;
|
||||
}
|
||||
.mdRow {
|
||||
padding: 8px 10px;
|
||||
}
|
||||
.mdescLeft {
|
||||
padding: 0px 8px 4px 8px;
|
||||
font-size: 80%;
|
||||
font-style: italic;
|
||||
background-color: #FAFAFA;
|
||||
border-top: 1px none #E0E0E0;
|
||||
border-right: 1px none #E0E0E0;
|
||||
border-bottom: 1px none #E0E0E0;
|
||||
border-left: 1px none #E0E0E0;
|
||||
margin: 0px;
|
||||
}
|
||||
.mdescRight {
|
||||
padding: 0px 8px 4px 8px;
|
||||
font-size: 80%;
|
||||
font-style: italic;
|
||||
background-color: #FAFAFA;
|
||||
border-top: 1px none #E0E0E0;
|
||||
border-right: 1px none #E0E0E0;
|
||||
border-bottom: 1px none #E0E0E0;
|
||||
border-left: 1px none #E0E0E0;
|
||||
margin: 0px;
|
||||
}
|
||||
.memItemLeft {
|
||||
padding: 1px 0px 0px 8px;
|
||||
margin: 4px;
|
||||
border-top-width: 1px;
|
||||
border-right-width: 1px;
|
||||
border-bottom-width: 1px;
|
||||
border-left-width: 1px;
|
||||
border-top-color: #E0E0E0;
|
||||
border-right-color: #E0E0E0;
|
||||
border-bottom-color: #E0E0E0;
|
||||
border-left-color: #E0E0E0;
|
||||
border-top-style: solid;
|
||||
border-right-style: none;
|
||||
border-bottom-style: none;
|
||||
border-left-style: none;
|
||||
background-color: #FAFAFA;
|
||||
font-size: 80%;
|
||||
}
|
||||
.memItemRight {
|
||||
padding: 1px 8px 0px 8px;
|
||||
margin: 4px;
|
||||
border-top-width: 1px;
|
||||
border-right-width: 1px;
|
||||
border-bottom-width: 1px;
|
||||
border-left-width: 1px;
|
||||
border-top-color: #E0E0E0;
|
||||
border-right-color: #E0E0E0;
|
||||
border-bottom-color: #E0E0E0;
|
||||
border-left-color: #E0E0E0;
|
||||
border-top-style: solid;
|
||||
border-right-style: none;
|
||||
border-bottom-style: none;
|
||||
border-left-style: none;
|
||||
background-color: #FAFAFA;
|
||||
font-size: 80%;
|
||||
}
|
||||
.memTemplItemLeft {
|
||||
padding: 1px 0px 0px 8px;
|
||||
margin: 4px;
|
||||
border-top-width: 1px;
|
||||
border-right-width: 1px;
|
||||
border-bottom-width: 1px;
|
||||
border-left-width: 1px;
|
||||
border-top-color: #E0E0E0;
|
||||
border-right-color: #E0E0E0;
|
||||
border-bottom-color: #E0E0E0;
|
||||
border-left-color: #E0E0E0;
|
||||
border-top-style: none;
|
||||
border-right-style: none;
|
||||
border-bottom-style: none;
|
||||
border-left-style: none;
|
||||
background-color: #FAFAFA;
|
||||
font-size: 80%;
|
||||
}
|
||||
.memTemplItemRight {
|
||||
padding: 1px 8px 0px 8px;
|
||||
margin: 4px;
|
||||
border-top-width: 1px;
|
||||
border-right-width: 1px;
|
||||
border-bottom-width: 1px;
|
||||
border-left-width: 1px;
|
||||
border-top-color: #E0E0E0;
|
||||
border-right-color: #E0E0E0;
|
||||
border-bottom-color: #E0E0E0;
|
||||
border-left-color: #E0E0E0;
|
||||
border-top-style: none;
|
||||
border-right-style: none;
|
||||
border-bottom-style: none;
|
||||
border-left-style: none;
|
||||
background-color: #FAFAFA;
|
||||
font-size: 80%;
|
||||
}
|
||||
.memTemplParams {
|
||||
padding: 1px 0px 0px 8px;
|
||||
margin: 4px;
|
||||
border-top-width: 1px;
|
||||
border-right-width: 1px;
|
||||
border-bottom-width: 1px;
|
||||
border-left-width: 1px;
|
||||
border-top-color: #E0E0E0;
|
||||
border-right-color: #E0E0E0;
|
||||
border-bottom-color: #E0E0E0;
|
||||
border-left-color: #E0E0E0;
|
||||
border-top-style: solid;
|
||||
border-right-style: none;
|
||||
border-bottom-style: none;
|
||||
border-left-style: none;
|
||||
color: #606060;
|
||||
background-color: #FAFAFA;
|
||||
font-size: 80%;
|
||||
}
|
||||
.search { color: #003399;
|
||||
font-weight: bold;
|
||||
}
|
||||
FORM.search {
|
||||
margin-bottom: 0px;
|
||||
margin-top: 0px;
|
||||
}
|
||||
INPUT.search { font-size: 75%;
|
||||
color: #000080;
|
||||
font-weight: normal;
|
||||
background-color: #eeeeff;
|
||||
}
|
||||
TD.tiny { font-size: 75%;
|
||||
}
|
||||
a {
|
||||
color: #252E78;
|
||||
}
|
||||
a:visited {
|
||||
color: #3D2185;
|
||||
}
|
||||
.dirtab { padding: 4px;
|
||||
border-collapse: collapse;
|
||||
border: 1px solid #b0b0b0;
|
||||
}
|
||||
TH.dirtab { background: #eeeeff;
|
||||
font-weight: bold;
|
||||
}
|
||||
HR { height: 1px;
|
||||
border: none;
|
||||
border-top: 1px solid black;
|
||||
}
|
||||
|
||||
/*
|
||||
* LLVM Modifications.
|
||||
* Note: Everything above here is generated with "doxygen -w htlm" command. See
|
||||
* "doxygen --help" for details. What follows are CSS overrides for LLVM
|
||||
* specific formatting. We want to keep the above so it can be replaced with
|
||||
* subsequent doxygen upgrades.
|
||||
*/
|
||||
|
||||
.footer {
|
||||
font-size: 80%;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.title {
|
||||
font-size: 25pt;
|
||||
color: black; background: url("http://llvm.org/img/lines.gif");
|
||||
font-weight: bold;
|
||||
border-width: 1px;
|
||||
border-style: solid none solid none;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
padding-left: 8pt;
|
||||
padding-top: 1px;
|
||||
padding-bottom: 2px
|
||||
}
|
||||
A:link {
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
font-weight: bolder;
|
||||
}
|
||||
A:visited {
|
||||
cursor: pointer;
|
||||
text-decoration: underline;
|
||||
font-weight: bolder;
|
||||
}
|
||||
A:hover {
|
||||
cursor: pointer;
|
||||
text-decoration: underline;
|
||||
font-weight: bolder;
|
||||
}
|
||||
A:active {
|
||||
cursor: pointer;
|
||||
text-decoration: underline;
|
||||
font-weight: bolder;
|
||||
font-style: italic;
|
||||
}
|
||||
H1 {
|
||||
text-align: center;
|
||||
font-size: 140%;
|
||||
font-weight: bold;
|
||||
}
|
||||
H2 {
|
||||
font-size: 120%;
|
||||
font-style: italic;
|
||||
}
|
||||
H3 {
|
||||
font-size: 100%;
|
||||
}
|
||||
A.qindex {}
|
||||
A.qindexRef {}
|
||||
A.el { text-decoration: none; font-weight: bold }
|
||||
A.elRef { font-weight: bold }
|
||||
A.code { text-decoration: none; font-weight: normal; color: #4444ee }
|
||||
A.codeRef { font-weight: normal; color: #4444ee }
|
||||
@@ -1,10 +0,0 @@
|
||||
<hr>
|
||||
<p class="footer">
|
||||
Generated on $datetime by <a href="http://www.doxygen.org">Doxygen
|
||||
$doxygenversion</a>.</p>
|
||||
|
||||
<p class="footer">
|
||||
See the <a href="http://clang.llvm.org">Main Clang Web Page</a> for more
|
||||
information.</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,9 +0,0 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1"/>
|
||||
<meta name="keywords" content="clang,LLVM,Low Level Virtual Machine,C,C++,doxygen,API,frontend,documentation"/>
|
||||
<meta name="description" content="C++ source code API documentation for clang."/>
|
||||
<title>clang: $title</title>
|
||||
<link href="doxygen.css" rel="stylesheet" type="text/css"/>
|
||||
</head><body>
|
||||
<p class="title">clang API Documentation</p>
|
||||
@@ -1,15 +0,0 @@
|
||||
/// @mainpage clang
|
||||
///
|
||||
/// @section main_intro Introduction
|
||||
/// Welcome to the clang project.
|
||||
///
|
||||
/// This documentation describes the @b internal software that makes
|
||||
/// up clang, not the @b external use of clang. There are no instructions
|
||||
/// here on how to use clang, only the APIs that make up the software. For
|
||||
/// usage instructions, please see the programmer's guide or reference
|
||||
/// manual.
|
||||
///
|
||||
/// @section main_caveat Caveat
|
||||
/// This documentation is generated directly from the source code with doxygen.
|
||||
/// Since clang is constantly under active development, what you're about to
|
||||
/// read is out of date!
|
||||
@@ -1,4 +0,0 @@
|
||||
<title>'clang' C frontend documentation</title>
|
||||
|
||||
None yet, sorry :(
|
||||
|
||||
@@ -1,253 +0,0 @@
|
||||
//===--- APValue.h - Union class for APFloat/APSInt/Complex -----*- 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 APValue class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_APVALUE_H
|
||||
#define LLVM_CLANG_AST_APVALUE_H
|
||||
|
||||
#include "llvm/ADT/APSInt.h"
|
||||
#include "llvm/ADT/APFloat.h"
|
||||
|
||||
namespace clang {
|
||||
class Expr;
|
||||
|
||||
/// APValue - This class implements a discriminated union of [uninitialized]
|
||||
/// [APSInt] [APFloat], [Complex APSInt] [Complex APFloat], [Expr + Offset].
|
||||
class APValue {
|
||||
typedef llvm::APSInt APSInt;
|
||||
typedef llvm::APFloat APFloat;
|
||||
public:
|
||||
enum ValueKind {
|
||||
Uninitialized,
|
||||
Int,
|
||||
Float,
|
||||
ComplexInt,
|
||||
ComplexFloat,
|
||||
LValue,
|
||||
Vector
|
||||
};
|
||||
private:
|
||||
ValueKind Kind;
|
||||
|
||||
struct ComplexAPSInt {
|
||||
APSInt Real, Imag;
|
||||
ComplexAPSInt() : Real(1), Imag(1) {}
|
||||
};
|
||||
struct ComplexAPFloat {
|
||||
APFloat Real, Imag;
|
||||
ComplexAPFloat() : Real(0.0), Imag(0.0) {}
|
||||
};
|
||||
|
||||
struct LV {
|
||||
Expr* Base;
|
||||
uint64_t Offset;
|
||||
};
|
||||
struct Vec {
|
||||
APValue *Elts;
|
||||
unsigned NumElts;
|
||||
Vec() : Elts(0), NumElts(0) {}
|
||||
~Vec() { delete[] Elts; }
|
||||
};
|
||||
|
||||
enum {
|
||||
MaxSize = (sizeof(ComplexAPSInt) > sizeof(ComplexAPFloat) ?
|
||||
sizeof(ComplexAPSInt) : sizeof(ComplexAPFloat))
|
||||
};
|
||||
|
||||
/// Data - space for the largest member in units of void*. This is an effort
|
||||
/// to ensure that the APSInt/APFloat values have proper alignment.
|
||||
void *Data[(MaxSize+sizeof(void*)-1)/sizeof(void*)];
|
||||
|
||||
public:
|
||||
APValue() : Kind(Uninitialized) {}
|
||||
explicit APValue(const APSInt &I) : Kind(Uninitialized) {
|
||||
MakeInt(); setInt(I);
|
||||
}
|
||||
explicit APValue(const APFloat &F) : Kind(Uninitialized) {
|
||||
MakeFloat(); setFloat(F);
|
||||
}
|
||||
explicit APValue(const APValue *E, unsigned N) : Kind(Uninitialized) {
|
||||
MakeVector(); setVector(E, N);
|
||||
}
|
||||
APValue(const APSInt &R, const APSInt &I) : Kind(Uninitialized) {
|
||||
MakeComplexInt(); setComplexInt(R, I);
|
||||
}
|
||||
APValue(const APFloat &R, const APFloat &I) : Kind(Uninitialized) {
|
||||
MakeComplexFloat(); setComplexFloat(R, I);
|
||||
}
|
||||
APValue(const APValue &RHS) : Kind(Uninitialized) {
|
||||
*this = RHS;
|
||||
}
|
||||
APValue(Expr* B, uint64_t O) : Kind(Uninitialized) {
|
||||
MakeLValue(); setLValue(B, O);
|
||||
}
|
||||
~APValue() {
|
||||
MakeUninit();
|
||||
}
|
||||
|
||||
ValueKind getKind() const { return Kind; }
|
||||
bool isUninit() const { return Kind == Uninitialized; }
|
||||
bool isInt() const { return Kind == Int; }
|
||||
bool isFloat() const { return Kind == Float; }
|
||||
bool isComplexInt() const { return Kind == ComplexInt; }
|
||||
bool isComplexFloat() const { return Kind == ComplexFloat; }
|
||||
bool isLValue() const { return Kind == LValue; }
|
||||
bool isVector() const { return Kind == Vector; }
|
||||
|
||||
void print(llvm::raw_ostream &OS) const;
|
||||
void dump() const;
|
||||
|
||||
APSInt &getInt() {
|
||||
assert(isInt() && "Invalid accessor");
|
||||
return *(APSInt*)(void*)Data;
|
||||
}
|
||||
const APSInt &getInt() const {
|
||||
return const_cast<APValue*>(this)->getInt();
|
||||
}
|
||||
|
||||
APFloat &getFloat() {
|
||||
assert(isFloat() && "Invalid accessor");
|
||||
return *(APFloat*)(void*)Data;
|
||||
}
|
||||
const APFloat &getFloat() const {
|
||||
return const_cast<APValue*>(this)->getFloat();
|
||||
}
|
||||
|
||||
APValue &getVectorElt(unsigned i) const {
|
||||
assert(isVector() && "Invalid accessor");
|
||||
return ((Vec*)(void*)Data)->Elts[i];
|
||||
}
|
||||
unsigned getVectorLength() const {
|
||||
assert(isVector() && "Invalid accessor");
|
||||
return ((Vec*)(void *)Data)->NumElts;
|
||||
}
|
||||
|
||||
APSInt &getComplexIntReal() {
|
||||
assert(isComplexInt() && "Invalid accessor");
|
||||
return ((ComplexAPSInt*)(void*)Data)->Real;
|
||||
}
|
||||
const APSInt &getComplexIntReal() const {
|
||||
return const_cast<APValue*>(this)->getComplexIntReal();
|
||||
}
|
||||
|
||||
APSInt &getComplexIntImag() {
|
||||
assert(isComplexInt() && "Invalid accessor");
|
||||
return ((ComplexAPSInt*)(void*)Data)->Imag;
|
||||
}
|
||||
const APSInt &getComplexIntImag() const {
|
||||
return const_cast<APValue*>(this)->getComplexIntImag();
|
||||
}
|
||||
|
||||
APFloat &getComplexFloatReal() {
|
||||
assert(isComplexFloat() && "Invalid accessor");
|
||||
return ((ComplexAPFloat*)(void*)Data)->Real;
|
||||
}
|
||||
const APFloat &getComplexFloatReal() const {
|
||||
return const_cast<APValue*>(this)->getComplexFloatReal();
|
||||
}
|
||||
|
||||
APFloat &getComplexFloatImag() {
|
||||
assert(isComplexFloat() && "Invalid accessor");
|
||||
return ((ComplexAPFloat*)(void*)Data)->Imag;
|
||||
}
|
||||
const APFloat &getComplexFloatImag() const {
|
||||
return const_cast<APValue*>(this)->getComplexFloatImag();
|
||||
}
|
||||
|
||||
Expr* getLValueBase() const {
|
||||
assert(isLValue() && "Invalid accessor");
|
||||
return ((const LV*)(const void*)Data)->Base;
|
||||
}
|
||||
uint64_t getLValueOffset() const {
|
||||
assert(isLValue() && "Invalid accessor");
|
||||
return ((const LV*)(const void*)Data)->Offset;
|
||||
}
|
||||
|
||||
void setInt(const APSInt &I) {
|
||||
assert(isInt() && "Invalid accessor");
|
||||
*(APSInt*)(void*)Data = I;
|
||||
}
|
||||
void setFloat(const APFloat &F) {
|
||||
assert(isFloat() && "Invalid accessor");
|
||||
*(APFloat*)(void*)Data = F;
|
||||
}
|
||||
void setVector(const APValue *E, unsigned N) {
|
||||
assert(isVector() && "Invalid accessor");
|
||||
((Vec*)(void*)Data)->Elts = new APValue[N];
|
||||
((Vec*)(void*)Data)->NumElts = N;
|
||||
for (unsigned i = 0; i != N; ++i)
|
||||
((Vec*)(void*)Data)->Elts[i] = E[i];
|
||||
}
|
||||
void setComplexInt(const APSInt &R, const APSInt &I) {
|
||||
assert(R.getBitWidth() == I.getBitWidth() &&
|
||||
"Invalid complex int (type mismatch).");
|
||||
assert(isComplexInt() && "Invalid accessor");
|
||||
((ComplexAPSInt*)(void*)Data)->Real = R;
|
||||
((ComplexAPSInt*)(void*)Data)->Imag = I;
|
||||
}
|
||||
void setComplexFloat(const APFloat &R, const APFloat &I) {
|
||||
assert(&R.getSemantics() == &I.getSemantics() &&
|
||||
"Invalid complex float (type mismatch).");
|
||||
assert(isComplexFloat() && "Invalid accessor");
|
||||
((ComplexAPFloat*)(void*)Data)->Real = R;
|
||||
((ComplexAPFloat*)(void*)Data)->Imag = I;
|
||||
}
|
||||
void setLValue(Expr *B, uint64_t O) {
|
||||
assert(isLValue() && "Invalid accessor");
|
||||
((LV*)(void*)Data)->Base = B;
|
||||
((LV*)(void*)Data)->Offset = O;
|
||||
}
|
||||
|
||||
const APValue &operator=(const APValue &RHS);
|
||||
|
||||
private:
|
||||
void MakeUninit();
|
||||
void MakeInt() {
|
||||
assert(isUninit() && "Bad state change");
|
||||
new ((void*)Data) APSInt(1);
|
||||
Kind = Int;
|
||||
}
|
||||
void MakeFloat() {
|
||||
assert(isUninit() && "Bad state change");
|
||||
new ((APFloat*)(void*)Data) APFloat(0.0);
|
||||
Kind = Float;
|
||||
}
|
||||
void MakeVector() {
|
||||
assert(isUninit() && "Bad state change");
|
||||
new ((Vec*)(void*)Data) Vec();
|
||||
Kind = Vector;
|
||||
}
|
||||
void MakeComplexInt() {
|
||||
assert(isUninit() && "Bad state change");
|
||||
new ((ComplexAPSInt*)(void*)Data) ComplexAPSInt();
|
||||
Kind = ComplexInt;
|
||||
}
|
||||
void MakeComplexFloat() {
|
||||
assert(isUninit() && "Bad state change");
|
||||
new ((ComplexAPFloat*)(void*)Data) ComplexAPFloat();
|
||||
Kind = ComplexFloat;
|
||||
}
|
||||
void MakeLValue() {
|
||||
assert(isUninit() && "Bad state change");
|
||||
new ((LV*)(void*)Data) LV();
|
||||
Kind = LValue;
|
||||
}
|
||||
};
|
||||
|
||||
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const APValue &V) {
|
||||
V.print(OS);
|
||||
return OS;
|
||||
}
|
||||
|
||||
} // end namespace clang.
|
||||
|
||||
#endif
|
||||
@@ -1,27 +0,0 @@
|
||||
//===--- AST.h - "Umbrella" header for AST library --------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the interface to the AST classes.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_AST_H
|
||||
#define LLVM_CLANG_AST_AST_H
|
||||
|
||||
// This header exports all AST interfaces.
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/DeclCXX.h"
|
||||
#include "clang/AST/DeclObjC.h"
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "clang/AST/ExprObjC.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/AST/StmtVisitor.h"
|
||||
|
||||
#endif
|
||||
@@ -1,60 +0,0 @@
|
||||
//===--- ASTConsumer.h - Abstract interface for reading ASTs ----*- 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 ASTConsumer class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_ASTCONSUMER_H
|
||||
#define LLVM_CLANG_AST_ASTCONSUMER_H
|
||||
|
||||
namespace clang {
|
||||
class ASTContext;
|
||||
class TranslationUnit;
|
||||
class Decl;
|
||||
class TagDecl;
|
||||
class HandleTagDeclDefinition;
|
||||
|
||||
/// ASTConsumer - This is an abstract interface that should be implemented by
|
||||
/// clients that read ASTs. This abstraction layer allows the client to be
|
||||
/// independent of the AST producer (e.g. parser vs AST dump file reader, etc).
|
||||
class ASTConsumer {
|
||||
public:
|
||||
virtual ~ASTConsumer();
|
||||
|
||||
/// Initialize - This is called to initialize the consumer, providing the
|
||||
/// ASTContext.
|
||||
virtual void Initialize(ASTContext &Context) {}
|
||||
|
||||
virtual void InitializeTU(TranslationUnit& TU);
|
||||
|
||||
/// HandleTopLevelDecl - Handle the specified top-level declaration. This is
|
||||
/// called by the parser to process every top-level Decl*. Note that D can
|
||||
/// be the head of a chain of Decls (e.g. for `int a, b` the chain will have
|
||||
/// two elements). Use Decl::getNextDeclarator() to walk the chain.
|
||||
virtual void HandleTopLevelDecl(Decl *D) {}
|
||||
|
||||
/// HandleTranslationUnit - This method is called when the ASTs for entire
|
||||
/// translation unit have been parsed.
|
||||
virtual void HandleTranslationUnit(TranslationUnit& TU) {}
|
||||
|
||||
/// HandleTagDeclDefinition - This callback is invoked each time a TagDecl
|
||||
/// (e.g. struct, union, enum, class) is completed. This allows the client to
|
||||
/// hack on the type, which can occur at any point in the file (because these
|
||||
/// can be defined in declspecs).
|
||||
virtual void HandleTagDeclDefinition(TagDecl *D) {}
|
||||
|
||||
/// PrintStats - If desired, print any statistics.
|
||||
virtual void PrintStats() {
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace clang.
|
||||
|
||||
#endif
|
||||
@@ -1,622 +0,0 @@
|
||||
//===--- ASTContext.h - Context to hold long-lived AST nodes ----*- 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 ASTContext interface.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_ASTCONTEXT_H
|
||||
#define LLVM_CLANG_AST_ASTCONTEXT_H
|
||||
|
||||
#include "clang/Basic/IdentifierTable.h"
|
||||
#include "clang/Basic/LangOptions.h"
|
||||
#include "clang/AST/Builtins.h"
|
||||
#include "clang/AST/DeclarationName.h"
|
||||
#include "clang/AST/DeclBase.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
#include "llvm/Bitcode/SerializationFwd.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
struct fltSemantics;
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
class ASTRecordLayout;
|
||||
class Expr;
|
||||
class IdentifierTable;
|
||||
class SelectorTable;
|
||||
class SourceManager;
|
||||
class TargetInfo;
|
||||
// Decls
|
||||
class Decl;
|
||||
class ObjCPropertyDecl;
|
||||
class RecordDecl;
|
||||
class TagDecl;
|
||||
class TranslationUnitDecl;
|
||||
class TypeDecl;
|
||||
class TypedefDecl;
|
||||
class TemplateTypeParmDecl;
|
||||
class FieldDecl;
|
||||
class ObjCIvarRefExpr;
|
||||
class ObjCIvarDecl;
|
||||
|
||||
/// ASTContext - This class holds long-lived AST nodes (such as types and
|
||||
/// decls) that can be referred to throughout the semantic analysis of a file.
|
||||
class ASTContext {
|
||||
std::vector<Type*> Types;
|
||||
llvm::FoldingSet<ASQualType> ASQualTypes;
|
||||
llvm::FoldingSet<ComplexType> ComplexTypes;
|
||||
llvm::FoldingSet<PointerType> PointerTypes;
|
||||
llvm::FoldingSet<BlockPointerType> BlockPointerTypes;
|
||||
llvm::FoldingSet<ReferenceType> ReferenceTypes;
|
||||
llvm::FoldingSet<MemberPointerType> MemberPointerTypes;
|
||||
llvm::FoldingSet<ConstantArrayType> ConstantArrayTypes;
|
||||
llvm::FoldingSet<IncompleteArrayType> IncompleteArrayTypes;
|
||||
std::vector<VariableArrayType*> VariableArrayTypes;
|
||||
std::vector<DependentSizedArrayType*> DependentSizedArrayTypes;
|
||||
llvm::FoldingSet<VectorType> VectorTypes;
|
||||
llvm::FoldingSet<FunctionTypeNoProto> FunctionTypeNoProtos;
|
||||
llvm::FoldingSet<FunctionTypeProto> FunctionTypeProtos;
|
||||
llvm::FoldingSet<ObjCQualifiedInterfaceType> ObjCQualifiedInterfaceTypes;
|
||||
llvm::FoldingSet<ObjCQualifiedIdType> ObjCQualifiedIdTypes;
|
||||
/// ASTRecordLayouts - A cache mapping from RecordDecls to ASTRecordLayouts.
|
||||
/// This is lazily created. This is intentionally not serialized.
|
||||
llvm::DenseMap<const RecordDecl*, const ASTRecordLayout*> ASTRecordLayouts;
|
||||
llvm::DenseMap<const ObjCInterfaceDecl*,
|
||||
const ASTRecordLayout*> ASTObjCInterfaces;
|
||||
|
||||
// FIXME: Shouldn't ASTRecordForInterface/ASTFieldForIvarRef and
|
||||
// addRecordToClass/getFieldDecl be part of the backend (i.e. CodeGenTypes and
|
||||
// CodeGenFunction)?
|
||||
llvm::DenseMap<const ObjCInterfaceDecl*,
|
||||
const RecordDecl*> ASTRecordForInterface;
|
||||
llvm::DenseMap<const ObjCIvarRefExpr*, const FieldDecl*> ASTFieldForIvarRef;
|
||||
|
||||
/// BuiltinVaListType - built-in va list type.
|
||||
/// This is initially null and set by Sema::LazilyCreateBuiltin when
|
||||
/// a builtin that takes a valist is encountered.
|
||||
QualType BuiltinVaListType;
|
||||
|
||||
/// ObjCIdType - a pseudo built-in typedef type (set by Sema).
|
||||
QualType ObjCIdType;
|
||||
const RecordType *IdStructType;
|
||||
|
||||
/// ObjCSelType - another pseudo built-in typedef type (set by Sema).
|
||||
QualType ObjCSelType;
|
||||
const RecordType *SelStructType;
|
||||
|
||||
/// ObjCProtoType - another pseudo built-in typedef type (set by Sema).
|
||||
QualType ObjCProtoType;
|
||||
const RecordType *ProtoStructType;
|
||||
|
||||
/// ObjCClassType - another pseudo built-in typedef type (set by Sema).
|
||||
QualType ObjCClassType;
|
||||
const RecordType *ClassStructType;
|
||||
|
||||
QualType ObjCConstantStringType;
|
||||
RecordDecl *CFConstantStringTypeDecl;
|
||||
|
||||
RecordDecl *ObjCFastEnumerationStateTypeDecl;
|
||||
|
||||
TranslationUnitDecl *TUDecl;
|
||||
|
||||
/// SourceMgr - The associated SourceManager object.
|
||||
SourceManager &SourceMgr;
|
||||
|
||||
/// LangOpts - The language options used to create the AST associated with
|
||||
/// this ASTContext object.
|
||||
LangOptions LangOpts;
|
||||
|
||||
/// MallocAlloc/BumpAlloc - The allocator objects used to create AST objects.
|
||||
bool FreeMemory;
|
||||
llvm::MallocAllocator MallocAlloc;
|
||||
llvm::BumpPtrAllocator BumpAlloc;
|
||||
public:
|
||||
TargetInfo &Target;
|
||||
IdentifierTable &Idents;
|
||||
SelectorTable &Selectors;
|
||||
DeclarationNameTable DeclarationNames;
|
||||
|
||||
SourceManager& getSourceManager() { return SourceMgr; }
|
||||
void *Allocate(unsigned Size, unsigned Align = 8) {
|
||||
return FreeMemory ? MallocAlloc.Allocate(Size, Align) :
|
||||
BumpAlloc.Allocate(Size, Align);
|
||||
}
|
||||
void Deallocate(void *Ptr) {
|
||||
if (FreeMemory)
|
||||
MallocAlloc.Deallocate(Ptr);
|
||||
}
|
||||
const LangOptions& getLangOptions() const { return LangOpts; }
|
||||
|
||||
FullSourceLoc getFullLoc(SourceLocation Loc) const {
|
||||
return FullSourceLoc(Loc,SourceMgr);
|
||||
}
|
||||
|
||||
TranslationUnitDecl *getTranslationUnitDecl() const { return TUDecl; }
|
||||
|
||||
/// This is intentionally not serialized. It is populated by the
|
||||
/// ASTContext ctor, and there are no external pointers/references to
|
||||
/// internal variables of BuiltinInfo.
|
||||
Builtin::Context BuiltinInfo;
|
||||
|
||||
// Builtin Types.
|
||||
QualType VoidTy;
|
||||
QualType BoolTy;
|
||||
QualType CharTy;
|
||||
QualType WCharTy; // [C++ 3.9.1p5]
|
||||
QualType SignedCharTy, ShortTy, IntTy, LongTy, LongLongTy;
|
||||
QualType UnsignedCharTy, UnsignedShortTy, UnsignedIntTy, UnsignedLongTy;
|
||||
QualType UnsignedLongLongTy;
|
||||
QualType FloatTy, DoubleTy, LongDoubleTy;
|
||||
QualType FloatComplexTy, DoubleComplexTy, LongDoubleComplexTy;
|
||||
QualType VoidPtrTy;
|
||||
QualType OverloadTy;
|
||||
QualType DependentTy;
|
||||
|
||||
ASTContext(const LangOptions& LOpts, SourceManager &SM, TargetInfo &t,
|
||||
IdentifierTable &idents, SelectorTable &sels,
|
||||
bool FreeMemory = true, unsigned size_reserve=0);
|
||||
|
||||
~ASTContext();
|
||||
|
||||
void PrintStats() const;
|
||||
const std::vector<Type*>& getTypes() const { return Types; }
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Type Constructors
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
/// getASQualType - Return the uniqued reference to the type for an address
|
||||
/// space qualified type with the specified type and address space. 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 getASQualType(QualType T, unsigned AddressSpace);
|
||||
|
||||
/// getComplexType - Return the uniqued reference to the type for a complex
|
||||
/// number with the specified element type.
|
||||
QualType getComplexType(QualType T);
|
||||
|
||||
/// getPointerType - Return the uniqued reference to the type for a pointer to
|
||||
/// the specified type.
|
||||
QualType getPointerType(QualType T);
|
||||
|
||||
/// getBlockPointerType - Return the uniqued reference to the type for a block
|
||||
/// of the specified type.
|
||||
QualType getBlockPointerType(QualType T);
|
||||
|
||||
/// getReferenceType - Return the uniqued reference to the type for a
|
||||
/// reference to the specified type.
|
||||
QualType getReferenceType(QualType T);
|
||||
|
||||
/// getMemberPointerType - Return the uniqued reference to the type for a
|
||||
/// member pointer to the specified type in the specified class. The class
|
||||
/// is a Type because it could be a dependent name.
|
||||
QualType getMemberPointerType(QualType T, const Type *Cls);
|
||||
|
||||
/// getVariableArrayType - Returns a non-unique reference to the type for a
|
||||
/// variable array of the specified element type.
|
||||
QualType getVariableArrayType(QualType EltTy, Expr *NumElts,
|
||||
ArrayType::ArraySizeModifier ASM,
|
||||
unsigned EltTypeQuals);
|
||||
|
||||
/// getDependentSizedArrayType - Returns a non-unique reference to
|
||||
/// the type for a dependently-sized array of the specified element
|
||||
/// type. FIXME: We will need these to be uniqued, or at least
|
||||
/// comparable, at some point.
|
||||
QualType getDependentSizedArrayType(QualType EltTy, Expr *NumElts,
|
||||
ArrayType::ArraySizeModifier ASM,
|
||||
unsigned EltTypeQuals);
|
||||
|
||||
/// getIncompleteArrayType - Returns a unique reference to the type for a
|
||||
/// incomplete array of the specified element type.
|
||||
QualType getIncompleteArrayType(QualType EltTy,
|
||||
ArrayType::ArraySizeModifier ASM,
|
||||
unsigned EltTypeQuals);
|
||||
|
||||
/// getConstantArrayType - Return the unique reference to the type for a
|
||||
/// constant array of the specified element type.
|
||||
QualType getConstantArrayType(QualType EltTy, const llvm::APInt &ArySize,
|
||||
ArrayType::ArraySizeModifier ASM,
|
||||
unsigned EltTypeQuals);
|
||||
|
||||
/// getVectorType - Return the unique reference to a vector type of
|
||||
/// the specified element type and size. VectorType must be a built-in type.
|
||||
QualType getVectorType(QualType VectorType, unsigned NumElts);
|
||||
|
||||
/// getExtVectorType - Return the unique reference to an extended vector type
|
||||
/// of the specified element type and size. VectorType must be a built-in
|
||||
/// type.
|
||||
QualType getExtVectorType(QualType VectorType, unsigned NumElts);
|
||||
|
||||
/// getFunctionTypeNoProto - Return a K&R style C function type like 'int()'.
|
||||
///
|
||||
QualType getFunctionTypeNoProto(QualType ResultTy);
|
||||
|
||||
/// getFunctionType - Return a normal function type with a typed argument
|
||||
/// list. isVariadic indicates whether the argument list includes '...'.
|
||||
QualType getFunctionType(QualType ResultTy, const QualType *ArgArray,
|
||||
unsigned NumArgs, bool isVariadic,
|
||||
unsigned TypeQuals);
|
||||
|
||||
/// getTypeDeclType - Return the unique reference to the type for
|
||||
/// the specified type declaration.
|
||||
QualType getTypeDeclType(TypeDecl *Decl, TypeDecl* PrevDecl=0);
|
||||
|
||||
/// getTypedefType - Return the unique reference to the type for the
|
||||
/// specified typename decl.
|
||||
QualType getTypedefType(TypedefDecl *Decl);
|
||||
QualType getTemplateTypeParmType(TemplateTypeParmDecl *Decl);
|
||||
QualType getObjCInterfaceType(ObjCInterfaceDecl *Decl);
|
||||
|
||||
/// getObjCQualifiedInterfaceType - Return a
|
||||
/// ObjCQualifiedInterfaceType type for the given interface decl and
|
||||
/// the conforming protocol list.
|
||||
QualType getObjCQualifiedInterfaceType(ObjCInterfaceDecl *Decl,
|
||||
ObjCProtocolDecl **ProtocolList, unsigned NumProtocols);
|
||||
|
||||
/// getObjCQualifiedIdType - Return an ObjCQualifiedIdType for a
|
||||
/// given 'id' and conforming protocol list.
|
||||
QualType getObjCQualifiedIdType(ObjCProtocolDecl **ProtocolList,
|
||||
unsigned NumProtocols);
|
||||
|
||||
|
||||
/// getTypeOfType - GCC extension.
|
||||
QualType getTypeOfExpr(Expr *e);
|
||||
QualType getTypeOfType(QualType t);
|
||||
|
||||
/// getTagDeclType - Return the unique reference to the type for the
|
||||
/// specified TagDecl (struct/union/class/enum) decl.
|
||||
QualType getTagDeclType(TagDecl *Decl);
|
||||
|
||||
/// getSizeType - Return the unique type for "size_t" (C99 7.17), defined
|
||||
/// in <stddef.h>. The sizeof operator requires this (C99 6.5.3.4p4).
|
||||
QualType getSizeType() const;
|
||||
|
||||
/// getWCharType - Return the unique type for "wchar_t" (C99 7.17), defined
|
||||
/// in <stddef.h>. Wide strings require this (C99 6.4.5p5).
|
||||
QualType getWCharType() const;
|
||||
|
||||
/// getSignedWCharType - Return the type of "signed wchar_t".
|
||||
/// Used when in C++, as a GCC extension.
|
||||
QualType getSignedWCharType() const;
|
||||
|
||||
/// getUnsignedWCharType - Return the type of "unsigned wchar_t".
|
||||
/// Used when in C++, as a GCC extension.
|
||||
QualType getUnsignedWCharType() const;
|
||||
|
||||
/// getPointerDiffType - Return the unique type for "ptrdiff_t" (ref?)
|
||||
/// defined in <stddef.h>. Pointer - pointer requires this (C99 6.5.6p9).
|
||||
QualType getPointerDiffType() const;
|
||||
|
||||
// getCFConstantStringType - Return the C structure type used to represent
|
||||
// constant CFStrings.
|
||||
QualType getCFConstantStringType();
|
||||
|
||||
// This setter/getter represents the ObjC type for an NSConstantString.
|
||||
void setObjCConstantStringInterface(ObjCInterfaceDecl *Decl);
|
||||
QualType getObjCConstantStringInterface() const {
|
||||
return ObjCConstantStringType;
|
||||
}
|
||||
|
||||
//// This gets the struct used to keep track of fast enumerations.
|
||||
QualType getObjCFastEnumerationStateType();
|
||||
|
||||
/// getObjCEncodingForType - Emit the ObjC type encoding for the
|
||||
/// given type into \arg S. If \arg NameFields is specified then
|
||||
/// record field names are also encoded.
|
||||
void getObjCEncodingForType(QualType t, std::string &S,
|
||||
FieldDecl *Field=NULL) const;
|
||||
|
||||
void getLegacyIntegralTypeEncoding(QualType &t) const;
|
||||
|
||||
// Put the string version of type qualifiers into S.
|
||||
void getObjCEncodingForTypeQualifier(Decl::ObjCDeclQualifier QT,
|
||||
std::string &S) const;
|
||||
|
||||
/// getObjCEncodingForMethodDecl - Return the encoded type for this method
|
||||
/// declaration.
|
||||
void getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl, std::string &S);
|
||||
|
||||
/// getObjCEncodingForPropertyDecl - Return the encoded type for
|
||||
/// this method declaration. If non-NULL, Container must be either
|
||||
/// an ObjCCategoryImplDecl or ObjCImplementationDecl; it should
|
||||
/// only be NULL when getting encodings for protocol properties.
|
||||
void getObjCEncodingForPropertyDecl(const ObjCPropertyDecl *PD,
|
||||
const Decl *Container,
|
||||
std::string &S);
|
||||
|
||||
/// getObjCEncodingTypeSize returns size of type for objective-c encoding
|
||||
/// purpose.
|
||||
int getObjCEncodingTypeSize(QualType t);
|
||||
|
||||
/// This setter/getter represents the ObjC 'id' type. It is setup lazily, by
|
||||
/// Sema. id is always a (typedef for a) pointer type, a pointer to a struct.
|
||||
QualType getObjCIdType() const { return ObjCIdType; }
|
||||
void setObjCIdType(TypedefDecl *Decl);
|
||||
|
||||
void setObjCSelType(TypedefDecl *Decl);
|
||||
QualType getObjCSelType() const { return ObjCSelType; }
|
||||
|
||||
void setObjCProtoType(QualType QT);
|
||||
QualType getObjCProtoType() const { return ObjCProtoType; }
|
||||
|
||||
/// This setter/getter repreents the ObjC 'Class' type. It is setup lazily, by
|
||||
/// Sema. 'Class' is always a (typedef for a) pointer type, a pointer to a
|
||||
/// struct.
|
||||
QualType getObjCClassType() const { return ObjCClassType; }
|
||||
void setObjCClassType(TypedefDecl *Decl);
|
||||
|
||||
void setBuiltinVaListType(QualType T);
|
||||
QualType getBuiltinVaListType() const { return BuiltinVaListType; }
|
||||
|
||||
private:
|
||||
QualType getFromTargetType(unsigned Type) const;
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Type Predicates.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
public:
|
||||
/// isObjCObjectPointerType - Returns true if type is an Objective-C pointer
|
||||
/// to an object type. This includes "id" and "Class" (two 'special' pointers
|
||||
/// to struct), Interface* (pointer to ObjCInterfaceType) and id<P> (qualified
|
||||
/// ID type).
|
||||
bool isObjCObjectPointerType(QualType Ty) const;
|
||||
|
||||
/// isObjCNSObjectType - Return true if this is an NSObject object with
|
||||
/// its NSObject attribute set.
|
||||
bool isObjCNSObjectType(QualType Ty) const;
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Type Sizing and Analysis
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
/// getFloatTypeSemantics - Return the APFloat 'semantics' for the specified
|
||||
/// scalar floating point type.
|
||||
const llvm::fltSemantics &getFloatTypeSemantics(QualType T) const;
|
||||
|
||||
/// getTypeInfo - Get the size and alignment of the specified complete type in
|
||||
/// bits.
|
||||
std::pair<uint64_t, unsigned> getTypeInfo(const Type *T);
|
||||
std::pair<uint64_t, unsigned> getTypeInfo(QualType T) {
|
||||
return getTypeInfo(T.getTypePtr());
|
||||
}
|
||||
|
||||
/// getTypeSize - Return the size of the specified type, in bits. This method
|
||||
/// does not work on incomplete types.
|
||||
uint64_t getTypeSize(QualType T) {
|
||||
return getTypeInfo(T).first;
|
||||
}
|
||||
uint64_t getTypeSize(const Type *T) {
|
||||
return getTypeInfo(T).first;
|
||||
}
|
||||
|
||||
/// getTypeAlign - Return the ABI-specified alignment of a type, in bits.
|
||||
/// This method does not work on incomplete types.
|
||||
unsigned getTypeAlign(QualType T) {
|
||||
return getTypeInfo(T).second;
|
||||
}
|
||||
unsigned getTypeAlign(const Type *T) {
|
||||
return getTypeInfo(T).second;
|
||||
}
|
||||
|
||||
/// getPreferredTypeAlign - Return the "preferred" alignment of the specified
|
||||
/// type for the current target in bits. This can be different than the ABI
|
||||
/// alignment in cases where it is beneficial for performance to overalign
|
||||
/// a data type.
|
||||
unsigned getPreferredTypeAlign(const Type *T);
|
||||
|
||||
/// getDeclAlign - Return the alignment of the specified decl that should be
|
||||
/// returned by __alignof(). Note that bitfields do not have a valid
|
||||
/// alignment, so this method will assert on them.
|
||||
unsigned getDeclAlign(const Decl *D);
|
||||
|
||||
/// getASTRecordLayout - Get or compute information about the layout of the
|
||||
/// specified record (struct/union/class), which indicates its size and field
|
||||
/// position information.
|
||||
const ASTRecordLayout &getASTRecordLayout(const RecordDecl *D);
|
||||
|
||||
const ASTRecordLayout &getASTObjCInterfaceLayout(const ObjCInterfaceDecl *D);
|
||||
const RecordDecl *addRecordToClass(const ObjCInterfaceDecl *D);
|
||||
const FieldDecl *getFieldDecl(const ObjCIvarRefExpr *MRef) {
|
||||
llvm::DenseMap<const ObjCIvarRefExpr *, const FieldDecl*>::iterator I
|
||||
= ASTFieldForIvarRef.find(MRef);
|
||||
assert (I != ASTFieldForIvarRef.end() && "Unable to find field_decl");
|
||||
return I->second;
|
||||
}
|
||||
void setFieldDecl(const ObjCInterfaceDecl *OI,
|
||||
const ObjCIvarDecl *Ivar,
|
||||
const ObjCIvarRefExpr *MRef);
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Type Operators
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
/// getCanonicalType - Return the canonical (structural) type corresponding to
|
||||
/// the specified potentially non-canonical type. The non-canonical version
|
||||
/// of a type may have many "decorated" versions of types. Decorators can
|
||||
/// include typedefs, 'typeof' operators, etc. The returned type is guaranteed
|
||||
/// to be free of any of these, allowing two canonical types to be compared
|
||||
/// for exact equality with a simple pointer comparison.
|
||||
QualType getCanonicalType(QualType T);
|
||||
const Type *getCanonicalType(const Type *T) {
|
||||
return T->getCanonicalTypeInternal().getTypePtr();
|
||||
}
|
||||
|
||||
/// Type Query functions. If the type is an instance of the specified class,
|
||||
/// return the Type pointer for the underlying maximally pretty type. This
|
||||
/// is a member of ASTContext because this may need to do some amount of
|
||||
/// canonicalization, e.g. to move type qualifiers into the element type.
|
||||
const ArrayType *getAsArrayType(QualType T);
|
||||
const ConstantArrayType *getAsConstantArrayType(QualType T) {
|
||||
return dyn_cast_or_null<ConstantArrayType>(getAsArrayType(T));
|
||||
}
|
||||
const VariableArrayType *getAsVariableArrayType(QualType T) {
|
||||
return dyn_cast_or_null<VariableArrayType>(getAsArrayType(T));
|
||||
}
|
||||
const IncompleteArrayType *getAsIncompleteArrayType(QualType T) {
|
||||
return dyn_cast_or_null<IncompleteArrayType>(getAsArrayType(T));
|
||||
}
|
||||
|
||||
/// getBaseElementType - Returns the innermost element type of a variable
|
||||
/// length array type. For example, will return "int" for int[m][n]
|
||||
QualType getBaseElementType(const VariableArrayType *VAT);
|
||||
|
||||
/// getArrayDecayedType - Return the properly qualified result of decaying the
|
||||
/// specified array type to a pointer. This operation is non-trivial when
|
||||
/// handling typedefs etc. The canonical type of "T" must be an array type,
|
||||
/// this returns a pointer to a properly qualified element of the array.
|
||||
///
|
||||
/// See C99 6.7.5.3p7 and C99 6.3.2.1p3.
|
||||
QualType getArrayDecayedType(QualType T);
|
||||
|
||||
/// getIntegerTypeOrder - Returns the highest ranked integer type:
|
||||
/// C99 6.3.1.8p1. If LHS > RHS, return 1. If LHS == RHS, return 0. If
|
||||
/// LHS < RHS, return -1.
|
||||
int getIntegerTypeOrder(QualType LHS, QualType RHS);
|
||||
|
||||
/// getFloatingTypeOrder - Compare the rank of the two specified floating
|
||||
/// point types, ignoring the domain of the type (i.e. 'double' ==
|
||||
/// '_Complex double'). If LHS > RHS, return 1. If LHS == RHS, return 0. If
|
||||
/// LHS < RHS, return -1.
|
||||
int getFloatingTypeOrder(QualType LHS, QualType RHS);
|
||||
|
||||
/// getFloatingTypeOfSizeWithinDomain - Returns a real floating
|
||||
/// point or a complex type (based on typeDomain/typeSize).
|
||||
/// 'typeDomain' is a real floating point or complex type.
|
||||
/// 'typeSize' is a real floating point or complex type.
|
||||
QualType getFloatingTypeOfSizeWithinDomain(QualType typeSize,
|
||||
QualType typeDomain) const;
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Type Compatibility Predicates
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
/// Compatibility predicates used to check assignment expressions.
|
||||
bool typesAreCompatible(QualType, QualType); // C99 6.2.7p1
|
||||
bool typesAreBlockCompatible(QualType lhs, QualType rhs);
|
||||
|
||||
bool isObjCIdType(QualType T) const {
|
||||
if (!IdStructType) // ObjC isn't enabled
|
||||
return false;
|
||||
return T->getAsStructureType() == IdStructType;
|
||||
}
|
||||
bool isObjCClassType(QualType T) const {
|
||||
if (!ClassStructType) // ObjC isn't enabled
|
||||
return false;
|
||||
return T->getAsStructureType() == ClassStructType;
|
||||
}
|
||||
bool isObjCSelType(QualType T) const {
|
||||
assert(SelStructType && "isObjCSelType used before 'SEL' type is built");
|
||||
return T->getAsStructureType() == SelStructType;
|
||||
}
|
||||
|
||||
// Check the safety of assignment from LHS to RHS
|
||||
bool canAssignObjCInterfaces(const ObjCInterfaceType *LHS,
|
||||
const ObjCInterfaceType *RHS);
|
||||
|
||||
// Functions for calculating composite types
|
||||
QualType mergeTypes(QualType, QualType);
|
||||
QualType mergeFunctionTypes(QualType, QualType);
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Integer Predicates
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
// The width of an integer, as defined in C99 6.2.6.2. This is the number
|
||||
// of bits in an integer type excluding any padding bits.
|
||||
unsigned getIntWidth(QualType T);
|
||||
|
||||
// Per C99 6.2.5p6, for every signed integer type, there is a corresponding
|
||||
// unsigned integer type. This method takes a signed type, and returns the
|
||||
// corresponding unsigned integer type.
|
||||
QualType getCorrespondingUnsignedType(QualType T);
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Type Iterators.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
typedef std::vector<Type*>::iterator type_iterator;
|
||||
typedef std::vector<Type*>::const_iterator const_type_iterator;
|
||||
|
||||
type_iterator types_begin() { return Types.begin(); }
|
||||
type_iterator types_end() { return Types.end(); }
|
||||
const_type_iterator types_begin() const { return Types.begin(); }
|
||||
const_type_iterator types_end() const { return Types.end(); }
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Serialization
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
void Emit(llvm::Serializer& S) const;
|
||||
static ASTContext* Create(llvm::Deserializer& D);
|
||||
|
||||
private:
|
||||
ASTContext(const ASTContext&); // DO NOT IMPLEMENT
|
||||
void operator=(const ASTContext&); // DO NOT IMPLEMENT
|
||||
|
||||
void InitBuiltinTypes();
|
||||
void InitBuiltinType(QualType &R, BuiltinType::Kind K);
|
||||
|
||||
// Return the ObjC type encoding for a given type.
|
||||
void getObjCEncodingForTypeImpl(QualType t, std::string &S,
|
||||
bool ExpandPointedToStructures,
|
||||
bool ExpandStructures,
|
||||
FieldDecl *Field,
|
||||
bool OutermostType = false,
|
||||
bool EncodingProperty = false) const;
|
||||
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
// operator new and delete aren't allowed inside namespaces.
|
||||
// The throw specifications are mandated by the standard.
|
||||
/// @brief Placement new for using the ASTContext's allocator.
|
||||
///
|
||||
/// This placement form of operator new uses the ASTContext's allocator for
|
||||
/// obtaining memory. It is a non-throwing new, which means that it returns
|
||||
/// null on error. (If that is what the allocator does. The current does, so if
|
||||
/// this ever changes, this operator will have to be changed, too.)
|
||||
/// Usage looks like this (assuming there's an ASTContext 'Context' in scope):
|
||||
/// @code
|
||||
/// // Default alignment (16)
|
||||
/// IntegerLiteral *Ex = new (Context) IntegerLiteral(arguments);
|
||||
/// // Specific alignment
|
||||
/// IntegerLiteral *Ex2 = new (Context, 8) IntegerLiteral(arguments);
|
||||
/// @endcode
|
||||
/// Please note that you cannot use delete on the pointer; it must be
|
||||
/// deallocated using an explicit destructor call followed by
|
||||
/// @c Context.getAllocator().Deallocate(Ptr)
|
||||
///
|
||||
/// @param Bytes The number of bytes to allocate. Calculated by the compiler.
|
||||
/// @param C The ASTContext that provides the allocator.
|
||||
/// @param Alignment The alignment of the allocated memory (if the allocator
|
||||
/// supports it, which the current one doesn't).
|
||||
/// @return The allocated memory. Could be NULL.
|
||||
inline void *operator new(size_t Bytes, clang::ASTContext &C,
|
||||
size_t Alignment = 16) throw () {
|
||||
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
|
||||
/// invoking it directly; see the new operator for more details. This operator
|
||||
/// is called implicitly by the compiler if a placement new expression using
|
||||
/// the ASTContext throws in the object constructor.
|
||||
inline void operator delete(void *Ptr, clang::ASTContext &C)
|
||||
throw () {
|
||||
C.Deallocate(Ptr);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,27 +0,0 @@
|
||||
//===--- DiagnosticAST.h - Diagnostics for the AST library ------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_DIAGNOSTICAST_H
|
||||
#define LLVM_CLANG_DIAGNOSTICAST_H
|
||||
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
|
||||
namespace clang {
|
||||
namespace diag {
|
||||
enum {
|
||||
#define DIAG(ENUM,FLAGS,DESC) ENUM,
|
||||
#define ASTSTART
|
||||
#include "clang/Basic/DiagnosticASTKinds.def"
|
||||
#undef DIAG
|
||||
NUM_BUILTIN_AST_DIAGNOSTICS
|
||||
};
|
||||
} // end namespace diag
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
@@ -1,468 +0,0 @@
|
||||
//===--- Attr.h - Classes for representing expressions ----------*- 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 Attr interface and subclasses.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_ATTR_H
|
||||
#define LLVM_CLANG_AST_ATTR_H
|
||||
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
|
||||
namespace clang {
|
||||
|
||||
/// Attr - This represents one attribute.
|
||||
class Attr {
|
||||
public:
|
||||
enum Kind {
|
||||
Alias,
|
||||
Aligned,
|
||||
AlwaysInline,
|
||||
Annotate,
|
||||
AsmLabel, // Represent GCC asm label extension.
|
||||
Constructor,
|
||||
Deprecated,
|
||||
Destructor,
|
||||
DLLImport,
|
||||
DLLExport,
|
||||
FastCall,
|
||||
Format,
|
||||
IBOutletKind, // Clang-specific. Use "Kind" suffix to not conflict with
|
||||
NonNull,
|
||||
NoReturn,
|
||||
NoThrow,
|
||||
ObjCGC,
|
||||
ObjCNSObject,
|
||||
Packed,
|
||||
StdCall,
|
||||
TransparentUnion,
|
||||
Unavailable,
|
||||
Unused,
|
||||
Visibility,
|
||||
Weak,
|
||||
Blocks,
|
||||
Const,
|
||||
Pure,
|
||||
Cleanup
|
||||
};
|
||||
|
||||
private:
|
||||
Attr *Next;
|
||||
Kind AttrKind;
|
||||
bool Inherited : 1;
|
||||
|
||||
protected:
|
||||
Attr(Kind AK) : Next(0), AttrKind(AK), Inherited(false) {}
|
||||
public:
|
||||
virtual ~Attr() {
|
||||
delete Next;
|
||||
}
|
||||
|
||||
Kind getKind() const { return AttrKind; }
|
||||
|
||||
Attr *getNext() { return Next; }
|
||||
const Attr *getNext() const { return Next; }
|
||||
void setNext(Attr *next) { Next = next; }
|
||||
|
||||
bool isInherited() const { return Inherited; }
|
||||
void setInherited(bool value) { Inherited = value; }
|
||||
|
||||
void addAttr(Attr *attr) {
|
||||
assert((attr != 0) && "addAttr(): attr is null");
|
||||
|
||||
// FIXME: This doesn't preserve the order in any way.
|
||||
attr->Next = Next;
|
||||
Next = attr;
|
||||
}
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *) { return true; }
|
||||
};
|
||||
|
||||
class PackedAttr : public Attr {
|
||||
unsigned Alignment;
|
||||
|
||||
public:
|
||||
PackedAttr(unsigned alignment) : Attr(Packed), Alignment(alignment) {}
|
||||
|
||||
/// getAlignment - The specified alignment in bits.
|
||||
unsigned getAlignment() const { return Alignment; }
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) {
|
||||
return A->getKind() == Packed;
|
||||
}
|
||||
static bool classof(const PackedAttr *A) { return true; }
|
||||
};
|
||||
|
||||
class AlignedAttr : public Attr {
|
||||
unsigned Alignment;
|
||||
public:
|
||||
AlignedAttr(unsigned alignment) : Attr(Aligned), Alignment(alignment) {}
|
||||
|
||||
/// getAlignment - The specified alignment in bits.
|
||||
unsigned getAlignment() const { return Alignment; }
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) {
|
||||
return A->getKind() == Aligned;
|
||||
}
|
||||
static bool classof(const AlignedAttr *A) { return true; }
|
||||
};
|
||||
|
||||
class AnnotateAttr : public Attr {
|
||||
std::string Annotation;
|
||||
public:
|
||||
AnnotateAttr(const std::string &ann) : Attr(Annotate), Annotation(ann) {}
|
||||
|
||||
const std::string& getAnnotation() const { return Annotation; }
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) {
|
||||
return A->getKind() == Annotate;
|
||||
}
|
||||
static bool classof(const AnnotateAttr *A) { return true; }
|
||||
};
|
||||
|
||||
class AsmLabelAttr : public Attr {
|
||||
std::string Label;
|
||||
public:
|
||||
AsmLabelAttr(const std::string &L) : Attr(AsmLabel), Label(L) {}
|
||||
|
||||
const std::string& getLabel() const { return Label; }
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) {
|
||||
return A->getKind() == AsmLabel;
|
||||
}
|
||||
static bool classof(const AsmLabelAttr *A) { return true; }
|
||||
};
|
||||
|
||||
class AlwaysInlineAttr : public Attr {
|
||||
public:
|
||||
AlwaysInlineAttr() : Attr(AlwaysInline) {}
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
|
||||
static bool classof(const Attr *A) { return A->getKind() == AlwaysInline; }
|
||||
static bool classof(const AlwaysInlineAttr *A) { return true; }
|
||||
};
|
||||
|
||||
class AliasAttr : public Attr {
|
||||
std::string Aliasee;
|
||||
public:
|
||||
AliasAttr(const std::string &aliasee) : Attr(Alias), Aliasee(aliasee) {}
|
||||
|
||||
const std::string& getAliasee() const { return Aliasee; }
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
|
||||
static bool classof(const Attr *A) { return A->getKind() == Alias; }
|
||||
static bool classof(const AliasAttr *A) { return true; }
|
||||
};
|
||||
|
||||
class ConstructorAttr : public Attr {
|
||||
int priority;
|
||||
public:
|
||||
ConstructorAttr(int p) : Attr(Constructor), priority(p) {}
|
||||
|
||||
int getPriority() const { return priority; }
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) { return A->getKind() == Constructor; }
|
||||
static bool classof(const ConstructorAttr *A) { return true; }
|
||||
};
|
||||
|
||||
class DestructorAttr : public Attr {
|
||||
int priority;
|
||||
public:
|
||||
DestructorAttr(int p) : Attr(Destructor), priority(p) {}
|
||||
|
||||
int getPriority() const { return priority; }
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) { return A->getKind() == Destructor; }
|
||||
static bool classof(const DestructorAttr *A) { return true; }
|
||||
};
|
||||
|
||||
class IBOutletAttr : public Attr {
|
||||
public:
|
||||
IBOutletAttr() : Attr(IBOutletKind) {}
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) {
|
||||
return A->getKind() == IBOutletKind;
|
||||
}
|
||||
static bool classof(const IBOutletAttr *A) { return true; }
|
||||
};
|
||||
|
||||
class NoReturnAttr : public Attr {
|
||||
public:
|
||||
NoReturnAttr() : Attr(NoReturn) {}
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
|
||||
static bool classof(const Attr *A) { return A->getKind() == NoReturn; }
|
||||
static bool classof(const NoReturnAttr *A) { return true; }
|
||||
};
|
||||
|
||||
class DeprecatedAttr : public Attr {
|
||||
public:
|
||||
DeprecatedAttr() : Attr(Deprecated) {}
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
|
||||
static bool classof(const Attr *A) { return A->getKind() == Deprecated; }
|
||||
static bool classof(const DeprecatedAttr *A) { return true; }
|
||||
};
|
||||
|
||||
class UnavailableAttr : public Attr {
|
||||
public:
|
||||
UnavailableAttr() : Attr(Unavailable) {}
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
|
||||
static bool classof(const Attr *A) { return A->getKind() == Unavailable; }
|
||||
static bool classof(const UnavailableAttr *A) { return true; }
|
||||
};
|
||||
|
||||
class UnusedAttr : public Attr {
|
||||
public:
|
||||
UnusedAttr() : Attr(Unused) {}
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) { return A->getKind() == Unused; }
|
||||
static bool classof(const UnusedAttr *A) { return true; }
|
||||
};
|
||||
|
||||
class WeakAttr : public Attr {
|
||||
public:
|
||||
WeakAttr() : Attr(Weak) {}
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
|
||||
static bool classof(const Attr *A) { return A->getKind() == Weak; }
|
||||
static bool classof(const WeakAttr *A) { return true; }
|
||||
};
|
||||
|
||||
class NoThrowAttr : public Attr {
|
||||
public:
|
||||
NoThrowAttr() : Attr(NoThrow) {}
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
|
||||
static bool classof(const Attr *A) { return A->getKind() == NoThrow; }
|
||||
static bool classof(const NoThrowAttr *A) { return true; }
|
||||
};
|
||||
|
||||
class ConstAttr : public Attr {
|
||||
public:
|
||||
ConstAttr() : Attr(Const) {}
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
|
||||
static bool classof(const Attr *A) { return A->getKind() == Const; }
|
||||
static bool classof(const ConstAttr *A) { return true; }
|
||||
};
|
||||
|
||||
class PureAttr : public Attr {
|
||||
public:
|
||||
PureAttr() : Attr(Pure) {}
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
|
||||
static bool classof(const Attr *A) { return A->getKind() == Pure; }
|
||||
static bool classof(const PureAttr *A) { return true; }
|
||||
};
|
||||
|
||||
class NonNullAttr : public Attr {
|
||||
unsigned* ArgNums;
|
||||
unsigned Size;
|
||||
public:
|
||||
NonNullAttr(unsigned* arg_nums = 0, unsigned size = 0) : Attr(NonNull),
|
||||
ArgNums(0), Size(0) {
|
||||
|
||||
if (size) {
|
||||
assert (arg_nums);
|
||||
ArgNums = new unsigned[size];
|
||||
Size = size;
|
||||
memcpy(ArgNums, arg_nums, sizeof(*ArgNums)*size);
|
||||
}
|
||||
}
|
||||
|
||||
virtual ~NonNullAttr() {
|
||||
delete [] ArgNums;
|
||||
}
|
||||
|
||||
bool isNonNull(unsigned arg) const {
|
||||
return ArgNums ? std::binary_search(ArgNums, ArgNums+Size, arg) : true;
|
||||
}
|
||||
|
||||
static bool classof(const Attr *A) { return A->getKind() == NonNull; }
|
||||
static bool classof(const NonNullAttr *A) { return true; }
|
||||
};
|
||||
|
||||
class FormatAttr : public Attr {
|
||||
std::string Type;
|
||||
int formatIdx, firstArg;
|
||||
public:
|
||||
FormatAttr(const std::string &type, int idx, int first) : Attr(Format),
|
||||
Type(type), formatIdx(idx), firstArg(first) {}
|
||||
|
||||
const std::string& getType() const { return Type; }
|
||||
int getFormatIdx() const { return formatIdx; }
|
||||
int getFirstArg() const { return firstArg; }
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
|
||||
static bool classof(const Attr *A) { return A->getKind() == Format; }
|
||||
static bool classof(const FormatAttr *A) { return true; }
|
||||
};
|
||||
|
||||
class VisibilityAttr : public Attr {
|
||||
public:
|
||||
/// @brief An enumeration for the kinds of visibility of symbols.
|
||||
enum VisibilityTypes {
|
||||
DefaultVisibility = 0,
|
||||
HiddenVisibility,
|
||||
ProtectedVisibility
|
||||
};
|
||||
private:
|
||||
VisibilityTypes VisibilityType;
|
||||
public:
|
||||
VisibilityAttr(VisibilityTypes v) : Attr(Visibility),
|
||||
VisibilityType(v) {}
|
||||
|
||||
VisibilityTypes getVisibility() const { return VisibilityType; }
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
|
||||
static bool classof(const Attr *A) { return A->getKind() == Visibility; }
|
||||
static bool classof(const VisibilityAttr *A) { return true; }
|
||||
};
|
||||
|
||||
class DLLImportAttr : public Attr {
|
||||
public:
|
||||
DLLImportAttr() : Attr(DLLImport) {}
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
|
||||
static bool classof(const Attr *A) { return A->getKind() == DLLImport; }
|
||||
static bool classof(const DLLImportAttr *A) { return true; }
|
||||
};
|
||||
|
||||
class DLLExportAttr : public Attr {
|
||||
public:
|
||||
DLLExportAttr() : Attr(DLLExport) {}
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
|
||||
static bool classof(const Attr *A) { return A->getKind() == DLLExport; }
|
||||
static bool classof(const DLLExportAttr *A) { return true; }
|
||||
};
|
||||
|
||||
class FastCallAttr : public Attr {
|
||||
public:
|
||||
FastCallAttr() : Attr(FastCall) {}
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
|
||||
static bool classof(const Attr *A) { return A->getKind() == FastCall; }
|
||||
static bool classof(const FastCallAttr *A) { return true; }
|
||||
};
|
||||
|
||||
class StdCallAttr : public Attr {
|
||||
public:
|
||||
StdCallAttr() : Attr(StdCall) {}
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
|
||||
static bool classof(const Attr *A) { return A->getKind() == StdCall; }
|
||||
static bool classof(const StdCallAttr *A) { return true; }
|
||||
};
|
||||
|
||||
class TransparentUnionAttr : public Attr {
|
||||
public:
|
||||
TransparentUnionAttr() : Attr(TransparentUnion) {}
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
|
||||
static bool classof(const Attr *A) { return A->getKind() == TransparentUnion; }
|
||||
static bool classof(const TransparentUnionAttr *A) { return true; }
|
||||
};
|
||||
|
||||
class ObjCGCAttr : public Attr {
|
||||
public:
|
||||
enum GCAttrTypes {
|
||||
Weak = 0,
|
||||
Strong
|
||||
};
|
||||
private:
|
||||
GCAttrTypes GCAttrType;
|
||||
public:
|
||||
ObjCGCAttr(GCAttrTypes t) : Attr(ObjCGC), GCAttrType(t) {}
|
||||
|
||||
GCAttrTypes getType() const { return GCAttrType; }
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
|
||||
static bool classof(const Attr *A) { return A->getKind() == ObjCGC; }
|
||||
static bool classof(const ObjCGCAttr *A) { return true; }
|
||||
};
|
||||
|
||||
class ObjCNSObjectAttr : public Attr {
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
public:
|
||||
ObjCNSObjectAttr() : Attr(ObjCNSObject) {}
|
||||
|
||||
static bool classof(const Attr *A) { return A->getKind() == ObjCNSObject; }
|
||||
static bool classof(const ObjCNSObjectAttr *A) { return true; }
|
||||
};
|
||||
|
||||
class BlocksAttr : public Attr {
|
||||
public:
|
||||
enum BlocksAttrTypes {
|
||||
ByRef = 0
|
||||
};
|
||||
private:
|
||||
BlocksAttrTypes BlocksAttrType;
|
||||
public:
|
||||
BlocksAttr(BlocksAttrTypes t) : Attr(Blocks), BlocksAttrType(t) {}
|
||||
|
||||
BlocksAttrTypes getType() const { return BlocksAttrType; }
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
|
||||
static bool classof(const Attr *A) { return A->getKind() == Blocks; }
|
||||
static bool classof(const BlocksAttr *A) { return true; }
|
||||
};
|
||||
|
||||
class FunctionDecl;
|
||||
|
||||
class CleanupAttr : public Attr {
|
||||
FunctionDecl *FD;
|
||||
|
||||
public:
|
||||
CleanupAttr(FunctionDecl *fd) : Attr(Cleanup), FD(fd) {}
|
||||
|
||||
const FunctionDecl *getFunctionDecl() const { return FD; }
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
|
||||
static bool classof(const Attr *A) { return A->getKind() == Cleanup; }
|
||||
static bool classof(const CleanupAttr *A) { return true; }
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
@@ -1,175 +0,0 @@
|
||||
//===--- Builtins.def - Builtin function info database ----------*- 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 standard builtin function database. Users of this file
|
||||
// must define the BUILTIN macro to make use of this information.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// FIXME: this needs to be the full list supported by GCC. Right now, I'm just
|
||||
// adding stuff on demand.
|
||||
//
|
||||
// FIXME: This should really be a .td file, but that requires modifying tblgen.
|
||||
// Perhaps tblgen should have plugins.
|
||||
|
||||
// The first value provided to the macro specifies the function name of the
|
||||
// builtin, and results in a clang::builtin::BIXX enum value for XX.
|
||||
|
||||
// The second value provided to the macro specifies the type of the function
|
||||
// (result value, then each argument) as follows:
|
||||
// v -> void
|
||||
// b -> boolean
|
||||
// c -> char
|
||||
// s -> short
|
||||
// i -> int
|
||||
// f -> float
|
||||
// d -> double
|
||||
// z -> size_t
|
||||
// F -> constant CFString
|
||||
// a -> __builtin_va_list
|
||||
// A -> "reference" to __builtin_va_list
|
||||
// V -> Vector, following num elements and a base type.
|
||||
// . -> "...". This may only occur at the end of the function list.
|
||||
//
|
||||
// Types maybe prefixed with the following modifiers:
|
||||
// L -> long (e.g. Li for 'long int')
|
||||
// LL -> long long
|
||||
// S -> signed
|
||||
// U -> unsigned
|
||||
//
|
||||
// Types may be postfixed with the following modifiers:
|
||||
// * -> pointer
|
||||
// & -> reference
|
||||
// C -> const
|
||||
|
||||
// The third value provided to the macro specifies information about attributes
|
||||
// of the function. These must be kept in sync with the predicates in the
|
||||
// Builtin::Context class. Currently we have:
|
||||
// n -> nothrow
|
||||
// c -> const
|
||||
// F -> this is a libc/libm function with a '__builtin_' prefix added.
|
||||
// FIXME: gcc has nonnull
|
||||
|
||||
// Standard libc/libm functions:
|
||||
BUILTIN(__builtin_huge_val, "d", "nc")
|
||||
BUILTIN(__builtin_huge_valf, "f", "nc")
|
||||
BUILTIN(__builtin_huge_vall, "Ld", "nc")
|
||||
BUILTIN(__builtin_inf , "d" , "nc")
|
||||
BUILTIN(__builtin_inff , "f" , "nc")
|
||||
BUILTIN(__builtin_infl , "Ld" , "nc")
|
||||
BUILTIN(__builtin_nan, "dcC*" , "ncF")
|
||||
BUILTIN(__builtin_nanf, "fcC*" , "ncF")
|
||||
BUILTIN(__builtin_nanl, "LdcC*", "ncF")
|
||||
BUILTIN(__builtin_nans, "dcC*" , "ncF")
|
||||
BUILTIN(__builtin_nansf, "fcC*" , "ncF")
|
||||
BUILTIN(__builtin_nansl, "LdcC*", "ncF")
|
||||
BUILTIN(__builtin_abs , "ii" , "ncF")
|
||||
BUILTIN(__builtin_fabs , "dd" , "ncF")
|
||||
BUILTIN(__builtin_fabsf, "ff" , "ncF")
|
||||
BUILTIN(__builtin_fabsl, "LdLd", "ncF")
|
||||
BUILTIN(__builtin_copysign, "ddd", "ncF")
|
||||
BUILTIN(__builtin_copysignf, "fff", "ncF")
|
||||
BUILTIN(__builtin_copysignl, "LdLdLd", "ncF")
|
||||
BUILTIN(__builtin_powi , "ddi" , "nc")
|
||||
BUILTIN(__builtin_powif, "ffi" , "nc")
|
||||
BUILTIN(__builtin_powil, "LdLdi", "nc")
|
||||
|
||||
// FP Comparisons.
|
||||
BUILTIN(__builtin_isgreater , "i.", "nc")
|
||||
BUILTIN(__builtin_isgreaterequal, "i.", "nc")
|
||||
BUILTIN(__builtin_isless , "i.", "nc")
|
||||
BUILTIN(__builtin_islessequal , "i.", "nc")
|
||||
BUILTIN(__builtin_islessgreater , "i.", "nc")
|
||||
BUILTIN(__builtin_isunordered , "i.", "nc")
|
||||
|
||||
// Builtins for arithmetic.
|
||||
BUILTIN(__builtin_clz , "iUi" , "nc")
|
||||
BUILTIN(__builtin_clzl , "iULi" , "nc")
|
||||
BUILTIN(__builtin_clzll, "iULLi", "nc")
|
||||
// TODO: int clzimax(uintmax_t)
|
||||
BUILTIN(__builtin_ctz , "iUi" , "nc")
|
||||
BUILTIN(__builtin_ctzl , "iULi" , "nc")
|
||||
BUILTIN(__builtin_ctzll, "iULLi", "nc")
|
||||
// TODO: int ctzimax(uintmax_t)
|
||||
BUILTIN(__builtin_ffs , "iUi" , "nc")
|
||||
BUILTIN(__builtin_ffsl , "iULi" , "nc")
|
||||
BUILTIN(__builtin_ffsll, "iULLi", "nc")
|
||||
BUILTIN(__builtin_parity , "iUi" , "nc")
|
||||
BUILTIN(__builtin_parityl , "iULi" , "nc")
|
||||
BUILTIN(__builtin_parityll, "iULLi", "nc")
|
||||
BUILTIN(__builtin_popcount , "iUi" , "nc")
|
||||
BUILTIN(__builtin_popcountl , "iULi" , "nc")
|
||||
BUILTIN(__builtin_popcountll, "iULLi", "nc")
|
||||
|
||||
// FIXME: These type signatures are not correct for targets with int != 32-bits
|
||||
// or with ULL != 64-bits.
|
||||
BUILTIN(__builtin_bswap32, "UiUi", "nc")
|
||||
BUILTIN(__builtin_bswap64, "ULLiULLi", "nc")
|
||||
|
||||
// Random GCC builtins
|
||||
BUILTIN(__builtin_constant_p, "Us.", "nc")
|
||||
BUILTIN(__builtin_classify_type, "i.", "nc")
|
||||
BUILTIN(__builtin___CFStringMakeConstantString, "FC*cC*", "nc")
|
||||
BUILTIN(__builtin_va_start, "vA.", "n")
|
||||
BUILTIN(__builtin_va_end, "vA", "n")
|
||||
BUILTIN(__builtin_va_copy, "vAA", "n")
|
||||
BUILTIN(__builtin_stdarg_start, "vA.", "n")
|
||||
BUILTIN(__builtin_bzero, "vv*z", "n")
|
||||
BUILTIN(__builtin_memcpy, "v*v*vC*z", "n")
|
||||
BUILTIN(__builtin_memmove, "v*v*vC*z", "n")
|
||||
BUILTIN(__builtin_memset, "v*v*iz", "n")
|
||||
BUILTIN(__builtin_return_address, "v*Ui", "n")
|
||||
BUILTIN(__builtin_frame_address, "v*Ui", "n")
|
||||
BUILTIN(__builtin_flt_rounds, "i", "nc")
|
||||
|
||||
// GCC Object size checking builtins
|
||||
BUILTIN(__builtin_object_size, "zv*i", "n")
|
||||
BUILTIN(__builtin___memcpy_chk, "v*v*vC*zz", "nF")
|
||||
BUILTIN(__builtin___memmove_chk, "v*v*vC*zz", "nF")
|
||||
BUILTIN(__builtin___mempcpy_chk, "v*v*vC*zz", "nF")
|
||||
BUILTIN(__builtin___memset_chk, "v*v*izz", "nF")
|
||||
BUILTIN(__builtin___stpcpy_chk, "c*c*cC*z", "nF")
|
||||
BUILTIN(__builtin___strcat_chk, "c*c*cC*z", "nF")
|
||||
BUILTIN(__builtin___strcpy_chk, "c*c*cC*z", "nF")
|
||||
BUILTIN(__builtin___strncat_chk, "c*c*cC*zz", "nF")
|
||||
BUILTIN(__builtin___strncpy_chk, "c*c*cC*zz", "nF")
|
||||
BUILTIN(__builtin___snprintf_chk, "ic*zizcC*.", "F") // FIXME: format printf attribute
|
||||
BUILTIN(__builtin___sprintf_chk, "ic*izcC*.", "F") // FIXME: format printf attribute
|
||||
BUILTIN(__builtin___vsnprintf_chk, "ic*zizcC*a", "F") // FIXME: format printf attribute
|
||||
BUILTIN(__builtin___vsprintf_chk, "ic*izcC*a", "F") // FIXME: format printf attribute
|
||||
//BUILTIN(__builtin___fprintf_chk, "i(FIXME:FILEPTR)icC*.", "F") // FIXME: format printf attribute
|
||||
BUILTIN(__builtin___printf_chk, "iicC*.", "F")
|
||||
//BUILTIN(__builtin___vfprintf_chk, "i(FIXME:FILEPTR)icC*a", "F") // FIXME: format printf attribute
|
||||
BUILTIN(__builtin___vprintf_chk, "iicC*a", "F") // FIXME: format printf attribute
|
||||
|
||||
BUILTIN(__builtin_expect, "iii" , "nc")
|
||||
BUILTIN(__builtin_prefetch, "vCv*.", "nc")
|
||||
BUILTIN(__builtin_trap, "v", "n")
|
||||
|
||||
BUILTIN(__builtin_shufflevector, "v." , "nc")
|
||||
|
||||
BUILTIN(__builtin_alloca, "v*z" , "n")
|
||||
|
||||
// Atomic operators builtin.
|
||||
BUILTIN(__sync_fetch_and_add,"ii*i", "n")
|
||||
BUILTIN(__sync_fetch_and_sub,"ii*i", "n")
|
||||
BUILTIN(__sync_fetch_and_min,"ii*i", "n")
|
||||
BUILTIN(__sync_fetch_and_max,"ii*i", "n")
|
||||
BUILTIN(__sync_fetch_and_umin,"UiUi*Ui", "n")
|
||||
BUILTIN(__sync_fetch_and_umax,"UiUi*Ui", "n")
|
||||
BUILTIN(__sync_fetch_and_and,"ii*i", "n")
|
||||
BUILTIN(__sync_fetch_and_or,"ii*i", "n")
|
||||
BUILTIN(__sync_fetch_and_xor,"ii*i", "n")
|
||||
BUILTIN(__sync_lock_test_and_set,"ii*i", "n")
|
||||
BUILTIN(__sync_val_compare_and_swap,"ii*ii", "n")
|
||||
|
||||
// LLVM instruction builtin
|
||||
BUILTIN(__builtin_llvm_memory_barrier,"vbbbbb", "n")
|
||||
|
||||
#undef BUILTIN
|
||||
@@ -1,95 +0,0 @@
|
||||
//===--- Builtins.h - Builtin function header -------------------*- 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 enum values for all the target-independent builtin
|
||||
// functions.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_BUILTINS_H
|
||||
#define LLVM_CLANG_AST_BUILTINS_H
|
||||
|
||||
#include <cstring>
|
||||
|
||||
namespace clang {
|
||||
class TargetInfo;
|
||||
class IdentifierTable;
|
||||
class ASTContext;
|
||||
class QualType;
|
||||
|
||||
namespace Builtin {
|
||||
enum ID {
|
||||
NotBuiltin = 0, // This is not a builtin function.
|
||||
#define BUILTIN(ID, TYPE, ATTRS) BI##ID,
|
||||
#include "clang/AST/Builtins.def"
|
||||
FirstTSBuiltin
|
||||
};
|
||||
|
||||
struct Info {
|
||||
const char *Name, *Type, *Attributes;
|
||||
|
||||
bool operator==(const Info &RHS) const {
|
||||
return !strcmp(Name, RHS.Name) &&
|
||||
!strcmp(Type, RHS.Type) &&
|
||||
!strcmp(Attributes, RHS.Attributes);
|
||||
}
|
||||
bool operator!=(const Info &RHS) const { return !(*this == RHS); }
|
||||
};
|
||||
|
||||
/// Builtin::Context - This holds information about target-independent and
|
||||
/// target-specific builtins, allowing easy queries by clients.
|
||||
class Context {
|
||||
const Info *TSRecords;
|
||||
unsigned NumTSRecords;
|
||||
public:
|
||||
Context() : TSRecords(0), NumTSRecords(0) {}
|
||||
|
||||
/// InitializeBuiltins - Mark the identifiers for all the builtins with their
|
||||
/// appropriate builtin ID # and mark any non-portable builtin identifiers as
|
||||
/// such.
|
||||
void InitializeBuiltins(IdentifierTable &Table, const TargetInfo &Target);
|
||||
|
||||
/// Builtin::GetName - Return the identifier name for the specified builtin,
|
||||
/// e.g. "__builtin_abs".
|
||||
const char *GetName(unsigned ID) const {
|
||||
return GetRecord(ID).Name;
|
||||
}
|
||||
|
||||
/// isConst - Return true if this function has no side effects and doesn't
|
||||
/// read memory.
|
||||
bool isConst(unsigned ID) const {
|
||||
return strchr(GetRecord(ID).Attributes, 'c') != 0;
|
||||
}
|
||||
|
||||
/// isNoThrow - Return true if we know this builtin never throws an exception.
|
||||
bool isNoThrow(unsigned ID) const {
|
||||
return strchr(GetRecord(ID).Attributes, 'n') != 0;
|
||||
}
|
||||
|
||||
/// isLibFunction - Return true if this is a builtin for a libc/libm function,
|
||||
/// with a "__builtin_" prefix (e.g. __builtin_abs).
|
||||
bool isLibFunction(unsigned ID) const {
|
||||
return strchr(GetRecord(ID).Attributes, 'F') != 0;
|
||||
}
|
||||
|
||||
/// hasVAListUse - Return true of the specified builtin uses __builtin_va_list
|
||||
/// as an operand or return type.
|
||||
bool hasVAListUse(unsigned ID) const {
|
||||
return strpbrk(GetRecord(ID).Type, "Aa") != 0;
|
||||
}
|
||||
|
||||
/// GetBuiltinType - Return the type for the specified builtin.
|
||||
QualType GetBuiltinType(unsigned ID, ASTContext &Context) const;
|
||||
private:
|
||||
const Info &GetRecord(unsigned ID) const;
|
||||
};
|
||||
|
||||
}
|
||||
} // end namespace clang
|
||||
#endif
|
||||
@@ -1,397 +0,0 @@
|
||||
//===--- CFG.h - Classes for representing and building CFGs------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the CFG and CFGBuilder classes for representing and
|
||||
// building Control-Flow Graphs (CFGs) from ASTs.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_CFG_H
|
||||
#define LLVM_CLANG_CFG_H
|
||||
|
||||
#include "llvm/ADT/GraphTraits.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include <cassert>
|
||||
|
||||
namespace clang {
|
||||
class Stmt;
|
||||
class Expr;
|
||||
class CFG;
|
||||
class PrinterHelper;
|
||||
class BlockEdge;
|
||||
|
||||
/// CFGBlock - Represents a single basic block in a source-level CFG.
|
||||
/// It consists of:
|
||||
///
|
||||
/// (1) A set of statements/expressions (which may contain subexpressions).
|
||||
/// (2) A "terminator" statement (not in the set of statements).
|
||||
/// (3) A list of successors and predecessors.
|
||||
///
|
||||
/// Terminator: The terminator represents the type of control-flow that occurs
|
||||
/// at the end of the basic block. The terminator is a Stmt* referring to an
|
||||
/// AST node that has control-flow: if-statements, breaks, loops, etc.
|
||||
/// If the control-flow is conditional, the condition expression will appear
|
||||
/// within the set of statements in the block (usually the last statement).
|
||||
///
|
||||
/// Predecessors: the order in the set of predecessors is arbitrary.
|
||||
///
|
||||
/// Successors: the order in the set of successors is NOT arbitrary. We
|
||||
/// currently have the following orderings based on the terminator:
|
||||
///
|
||||
/// Terminator Successor Ordering
|
||||
/// -----------------------------------------------------
|
||||
/// if Then Block; Else Block
|
||||
/// ? operator LHS expression; RHS expression
|
||||
/// &&, || expression that uses result of && or ||, RHS
|
||||
///
|
||||
class CFGBlock {
|
||||
typedef std::vector<Stmt*> StatementListTy;
|
||||
/// Stmts - The set of statements in the basic block.
|
||||
StatementListTy Stmts;
|
||||
|
||||
/// Label - An (optional) label that prefixes the executable
|
||||
/// statements in the block. When this variable is non-NULL, it is
|
||||
/// either an instance of LabelStmt or SwitchCase.
|
||||
Stmt* Label;
|
||||
|
||||
/// Terminator - The terminator for a basic block that
|
||||
/// indicates the type of control-flow that occurs between a block
|
||||
/// and its successors.
|
||||
Stmt* Terminator;
|
||||
|
||||
/// BlockID - A numerical ID assigned to a CFGBlock during construction
|
||||
/// of the CFG.
|
||||
unsigned BlockID;
|
||||
|
||||
/// Predecessors/Successors - Keep track of the predecessor / successor
|
||||
/// CFG blocks.
|
||||
typedef std::vector<CFGBlock*> AdjacentBlocks;
|
||||
AdjacentBlocks Preds;
|
||||
AdjacentBlocks Succs;
|
||||
|
||||
public:
|
||||
explicit CFGBlock(unsigned blockid) : Label(NULL), Terminator(NULL),
|
||||
BlockID(blockid) {}
|
||||
~CFGBlock() {};
|
||||
|
||||
// Statement iterators
|
||||
typedef StatementListTy::iterator iterator;
|
||||
typedef StatementListTy::const_iterator const_iterator;
|
||||
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
|
||||
typedef std::reverse_iterator<iterator> reverse_iterator;
|
||||
|
||||
Stmt* front() const { return Stmts.front(); }
|
||||
Stmt* back() const { return Stmts.back(); }
|
||||
|
||||
iterator begin() { return Stmts.begin(); }
|
||||
iterator end() { return Stmts.end(); }
|
||||
const_iterator begin() const { return Stmts.begin(); }
|
||||
const_iterator end() const { return Stmts.end(); }
|
||||
|
||||
reverse_iterator rbegin() { return Stmts.rbegin(); }
|
||||
reverse_iterator rend() { return Stmts.rend(); }
|
||||
const_reverse_iterator rbegin() const { return Stmts.rbegin(); }
|
||||
const_reverse_iterator rend() const { return Stmts.rend(); }
|
||||
|
||||
unsigned size() const { return Stmts.size(); }
|
||||
bool empty() const { return Stmts.empty(); }
|
||||
|
||||
Stmt* operator[](size_t i) const { assert (i < size()); return Stmts[i]; }
|
||||
|
||||
// CFG iterators
|
||||
typedef AdjacentBlocks::iterator pred_iterator;
|
||||
typedef AdjacentBlocks::const_iterator const_pred_iterator;
|
||||
typedef AdjacentBlocks::reverse_iterator pred_reverse_iterator;
|
||||
typedef AdjacentBlocks::const_reverse_iterator const_pred_reverse_iterator;
|
||||
|
||||
typedef AdjacentBlocks::iterator succ_iterator;
|
||||
typedef AdjacentBlocks::const_iterator const_succ_iterator;
|
||||
typedef AdjacentBlocks::reverse_iterator succ_reverse_iterator;
|
||||
typedef AdjacentBlocks::const_reverse_iterator const_succ_reverse_iterator;
|
||||
|
||||
pred_iterator pred_begin() { return Preds.begin(); }
|
||||
pred_iterator pred_end() { return Preds.end(); }
|
||||
const_pred_iterator pred_begin() const { return Preds.begin(); }
|
||||
const_pred_iterator pred_end() const { return Preds.end(); }
|
||||
|
||||
pred_reverse_iterator pred_rbegin() { return Preds.rbegin(); }
|
||||
pred_reverse_iterator pred_rend() { return Preds.rend(); }
|
||||
const_pred_reverse_iterator pred_rbegin() const { return Preds.rbegin(); }
|
||||
const_pred_reverse_iterator pred_rend() const { return Preds.rend(); }
|
||||
|
||||
succ_iterator succ_begin() { return Succs.begin(); }
|
||||
succ_iterator succ_end() { return Succs.end(); }
|
||||
const_succ_iterator succ_begin() const { return Succs.begin(); }
|
||||
const_succ_iterator succ_end() const { return Succs.end(); }
|
||||
|
||||
succ_reverse_iterator succ_rbegin() { return Succs.rbegin(); }
|
||||
succ_reverse_iterator succ_rend() { return Succs.rend(); }
|
||||
const_succ_reverse_iterator succ_rbegin() const { return Succs.rbegin(); }
|
||||
const_succ_reverse_iterator succ_rend() const { return Succs.rend(); }
|
||||
|
||||
unsigned succ_size() const { return Succs.size(); }
|
||||
bool succ_empty() const { return Succs.empty(); }
|
||||
|
||||
unsigned pred_size() const { return Preds.size(); }
|
||||
bool pred_empty() const { return Preds.empty(); }
|
||||
|
||||
// Manipulation of block contents
|
||||
|
||||
void appendStmt(Stmt* Statement) { Stmts.push_back(Statement); }
|
||||
void setTerminator(Stmt* Statement) { Terminator = Statement; }
|
||||
void setLabel(Stmt* Statement) { Label = Statement; }
|
||||
|
||||
Stmt* getTerminator() { return Terminator; }
|
||||
const Stmt* getTerminator() const { return Terminator; }
|
||||
|
||||
Stmt* getTerminatorCondition();
|
||||
|
||||
const Stmt* getTerminatorCondition() const {
|
||||
return const_cast<CFGBlock*>(this)->getTerminatorCondition();
|
||||
}
|
||||
|
||||
bool hasBinaryBranchTerminator() const;
|
||||
|
||||
Stmt* getLabel() { return Label; }
|
||||
const Stmt* getLabel() const { return Label; }
|
||||
|
||||
void reverseStmts();
|
||||
|
||||
void addSuccessor(CFGBlock* Block) {
|
||||
Block->Preds.push_back(this);
|
||||
Succs.push_back(Block);
|
||||
}
|
||||
|
||||
unsigned getBlockID() const { return BlockID; }
|
||||
|
||||
void dump(const CFG* cfg) const;
|
||||
void print(llvm::raw_ostream& OS, const CFG* cfg) const;
|
||||
void printTerminator(llvm::raw_ostream& OS) const;
|
||||
};
|
||||
|
||||
|
||||
/// CFG - Represents a source-level, intra-procedural CFG that represents the
|
||||
/// control-flow of a Stmt. The Stmt can represent an entire function body,
|
||||
/// or a single expression. A CFG will always contain one empty block that
|
||||
/// represents the Exit point of the CFG. A CFG will also contain a designated
|
||||
/// Entry block. The CFG solely represents control-flow; it consists of
|
||||
/// CFGBlocks which are simply containers of Stmt*'s in the AST the CFG
|
||||
/// was constructed from.
|
||||
class CFG {
|
||||
public:
|
||||
//===--------------------------------------------------------------------===//
|
||||
// CFG Construction & Manipulation.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
/// buildCFG - Builds a CFG from an AST. The responsibility to free the
|
||||
/// constructed CFG belongs to the caller.
|
||||
static CFG* buildCFG(Stmt* AST);
|
||||
|
||||
/// createBlock - Create a new block in the CFG. The CFG owns the block;
|
||||
/// the caller should not directly free it.
|
||||
CFGBlock* createBlock();
|
||||
|
||||
/// setEntry - Set the entry block of the CFG. This is typically used
|
||||
/// only during CFG construction. Most CFG clients expect that the
|
||||
/// entry block has no predecessors and contains no statements.
|
||||
void setEntry(CFGBlock *B) { Entry = B; }
|
||||
|
||||
/// setExit - Set the exit block of the CFG. This is typically used
|
||||
/// only during CFG construction. Most CFG clients expect that the
|
||||
/// exit block has no successors and contains no statements.
|
||||
void setIndirectGotoBlock(CFGBlock* B) { IndirectGotoBlock = B; }
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Block Iterators
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
typedef std::list<CFGBlock> CFGBlockListTy;
|
||||
|
||||
typedef CFGBlockListTy::iterator iterator;
|
||||
typedef CFGBlockListTy::const_iterator const_iterator;
|
||||
typedef std::reverse_iterator<iterator> reverse_iterator;
|
||||
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
|
||||
|
||||
CFGBlock& front() { return Blocks.front(); }
|
||||
CFGBlock& back() { return Blocks.back(); }
|
||||
|
||||
iterator begin() { return Blocks.begin(); }
|
||||
iterator end() { return Blocks.end(); }
|
||||
const_iterator begin() const { return Blocks.begin(); }
|
||||
const_iterator end() const { return Blocks.end(); }
|
||||
|
||||
reverse_iterator rbegin() { return Blocks.rbegin(); }
|
||||
reverse_iterator rend() { return Blocks.rend(); }
|
||||
const_reverse_iterator rbegin() const { return Blocks.rbegin(); }
|
||||
const_reverse_iterator rend() const { return Blocks.rend(); }
|
||||
|
||||
CFGBlock& getEntry() { return *Entry; }
|
||||
const CFGBlock& getEntry() const { return *Entry; }
|
||||
CFGBlock& getExit() { return *Exit; }
|
||||
const CFGBlock& getExit() const { return *Exit; }
|
||||
|
||||
CFGBlock* getIndirectGotoBlock() { return IndirectGotoBlock; }
|
||||
const CFGBlock* getIndirectGotoBlock() const { return IndirectGotoBlock; }
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Member templates useful for various batch operations over CFGs.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
template <typename CALLBACK>
|
||||
void VisitBlockStmts(CALLBACK& O) const {
|
||||
for (const_iterator I=begin(), E=end(); I != E; ++I)
|
||||
for (CFGBlock::const_iterator BI=I->begin(), BE=I->end(); BI != BE; ++BI)
|
||||
O(*BI);
|
||||
}
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// CFG Introspection.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
struct BlkExprNumTy {
|
||||
const signed Idx;
|
||||
explicit BlkExprNumTy(signed idx) : Idx(idx) {}
|
||||
explicit BlkExprNumTy() : Idx(-1) {}
|
||||
operator bool() const { return Idx >= 0; }
|
||||
operator unsigned() const { assert(Idx >=0); return (unsigned) Idx; }
|
||||
};
|
||||
|
||||
bool isBlkExpr(const Stmt* S) { return getBlkExprNum(S); }
|
||||
BlkExprNumTy getBlkExprNum(const Stmt* S);
|
||||
unsigned getNumBlkExprs();
|
||||
|
||||
unsigned getNumBlockIDs() const { return NumBlockIDs; }
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// CFG Debugging: Pretty-Printing and Visualization.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
void viewCFG() const;
|
||||
void print(llvm::raw_ostream& OS) const;
|
||||
void dump() const;
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Internal: constructors and data.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
CFG() : Entry(NULL), Exit(NULL), IndirectGotoBlock(NULL), NumBlockIDs(0),
|
||||
BlkExprMap(NULL) {};
|
||||
|
||||
~CFG();
|
||||
|
||||
llvm::BumpPtrAllocator& getAllocator() {
|
||||
return Alloc;
|
||||
}
|
||||
|
||||
private:
|
||||
CFGBlock* Entry;
|
||||
CFGBlock* Exit;
|
||||
CFGBlock* IndirectGotoBlock; // Special block to contain collective dispatch
|
||||
// for indirect gotos
|
||||
CFGBlockListTy Blocks;
|
||||
unsigned NumBlockIDs;
|
||||
|
||||
// BlkExprMap - An opaque pointer to prevent inclusion of DenseMap.h.
|
||||
// It represents a map from Expr* to integers to record the set of
|
||||
// block-level expressions and their "statement number" in the CFG.
|
||||
void* BlkExprMap;
|
||||
|
||||
/// Alloc - An internal allocator.
|
||||
llvm::BumpPtrAllocator Alloc;
|
||||
};
|
||||
} // end namespace clang
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// GraphTraits specializations for CFG basic block graphs (source-level CFGs)
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace llvm {
|
||||
|
||||
// Traits for: CFGBlock
|
||||
|
||||
template <> struct GraphTraits<clang::CFGBlock* > {
|
||||
typedef clang::CFGBlock NodeType;
|
||||
typedef clang::CFGBlock::succ_iterator ChildIteratorType;
|
||||
|
||||
static NodeType* getEntryNode(clang::CFGBlock* BB)
|
||||
{ return BB; }
|
||||
|
||||
static inline ChildIteratorType child_begin(NodeType* N)
|
||||
{ return N->succ_begin(); }
|
||||
|
||||
static inline ChildIteratorType child_end(NodeType* N)
|
||||
{ return N->succ_end(); }
|
||||
};
|
||||
|
||||
template <> struct GraphTraits<const clang::CFGBlock* > {
|
||||
typedef const clang::CFGBlock NodeType;
|
||||
typedef clang::CFGBlock::const_succ_iterator ChildIteratorType;
|
||||
|
||||
static NodeType* getEntryNode(const clang::CFGBlock* BB)
|
||||
{ return BB; }
|
||||
|
||||
static inline ChildIteratorType child_begin(NodeType* N)
|
||||
{ return N->succ_begin(); }
|
||||
|
||||
static inline ChildIteratorType child_end(NodeType* N)
|
||||
{ return N->succ_end(); }
|
||||
};
|
||||
|
||||
template <> struct GraphTraits<Inverse<const clang::CFGBlock*> > {
|
||||
typedef const clang::CFGBlock NodeType;
|
||||
typedef clang::CFGBlock::const_pred_iterator ChildIteratorType;
|
||||
|
||||
static NodeType *getEntryNode(Inverse<const clang::CFGBlock*> G)
|
||||
{ return G.Graph; }
|
||||
|
||||
static inline ChildIteratorType child_begin(NodeType* N)
|
||||
{ return N->pred_begin(); }
|
||||
|
||||
static inline ChildIteratorType child_end(NodeType* N)
|
||||
{ return N->pred_end(); }
|
||||
};
|
||||
|
||||
// Traits for: CFG
|
||||
|
||||
template <> struct GraphTraits<clang::CFG* >
|
||||
: public GraphTraits<clang::CFGBlock* > {
|
||||
|
||||
typedef clang::CFG::iterator nodes_iterator;
|
||||
|
||||
static NodeType *getEntryNode(clang::CFG* F) { return &F->getEntry(); }
|
||||
static nodes_iterator nodes_begin(clang::CFG* F) { return F->begin(); }
|
||||
static nodes_iterator nodes_end(clang::CFG* F) { return F->end(); }
|
||||
};
|
||||
|
||||
template <> struct GraphTraits< const clang::CFG* >
|
||||
: public GraphTraits< const clang::CFGBlock* > {
|
||||
|
||||
typedef clang::CFG::const_iterator nodes_iterator;
|
||||
|
||||
static NodeType *getEntryNode( const clang::CFG* F) { return &F->getEntry(); }
|
||||
static nodes_iterator nodes_begin( const clang::CFG* F) { return F->begin(); }
|
||||
static nodes_iterator nodes_end( const clang::CFG* F) { return F->end(); }
|
||||
};
|
||||
|
||||
template <> struct GraphTraits<Inverse<const clang::CFG*> >
|
||||
: public GraphTraits<Inverse<const clang::CFGBlock*> > {
|
||||
|
||||
typedef clang::CFG::const_iterator nodes_iterator;
|
||||
|
||||
static NodeType *getEntryNode(const clang::CFG* F) { return &F->getExit(); }
|
||||
static nodes_iterator nodes_begin(const clang::CFG* F) { return F->begin();}
|
||||
static nodes_iterator nodes_end(const clang::CFG* F) { return F->end(); }
|
||||
};
|
||||
|
||||
} // end llvm namespace
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,892 +0,0 @@
|
||||
//===-- DeclBase.h - Base Classes for representing declarations *- 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 Decl and DeclContext interfaces.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_DECLBASE_H
|
||||
#define LLVM_CLANG_AST_DECLBASE_H
|
||||
|
||||
#include "clang/AST/Attr.h"
|
||||
#include "clang/AST/Type.h"
|
||||
// FIXME: Layering violation
|
||||
#include "clang/Parse/AccessSpecifier.h"
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "llvm/ADT/PointerIntPair.h"
|
||||
|
||||
namespace clang {
|
||||
class DeclContext;
|
||||
class TranslationUnitDecl;
|
||||
class NamespaceDecl;
|
||||
class NamedDecl;
|
||||
class FunctionDecl;
|
||||
class CXXRecordDecl;
|
||||
class EnumDecl;
|
||||
class ObjCMethodDecl;
|
||||
class ObjCContainerDecl;
|
||||
class ObjCInterfaceDecl;
|
||||
class ObjCCategoryDecl;
|
||||
class ObjCProtocolDecl;
|
||||
class ObjCImplementationDecl;
|
||||
class ObjCCategoryImplDecl;
|
||||
class LinkageSpecDecl;
|
||||
class BlockDecl;
|
||||
class DeclarationName;
|
||||
|
||||
/// Decl - This represents one declaration (or definition), e.g. a variable,
|
||||
/// typedef, function, struct, etc.
|
||||
///
|
||||
class Decl {
|
||||
public:
|
||||
/// \brief Lists the kind of concrete classes of Decl.
|
||||
enum Kind {
|
||||
#define DECL(Derived, Base) Derived,
|
||||
#define DECL_RANGE(CommonBase, Start, End) \
|
||||
CommonBase##First = Start, CommonBase##Last = End,
|
||||
#define LAST_DECL_RANGE(CommonBase, Start, End) \
|
||||
CommonBase##First = Start, CommonBase##Last = End
|
||||
#include "clang/AST/DeclNodes.def"
|
||||
};
|
||||
|
||||
/// IdentifierNamespace - According to C99 6.2.3, there are four namespaces,
|
||||
/// labels, tags, members and ordinary identifiers. These are meant
|
||||
/// as bitmasks, so that searches in C++ can look into the "tag" namespace
|
||||
/// during ordinary lookup.
|
||||
enum IdentifierNamespace {
|
||||
IDNS_Label = 0x1,
|
||||
IDNS_Tag = 0x2,
|
||||
IDNS_Member = 0x4,
|
||||
IDNS_Ordinary = 0x8
|
||||
};
|
||||
|
||||
/// ObjCDeclQualifier - Qualifier used on types in method declarations
|
||||
/// for remote messaging. They are meant for the arguments though and
|
||||
/// applied to the Decls (ObjCMethodDecl and ParmVarDecl).
|
||||
enum ObjCDeclQualifier {
|
||||
OBJC_TQ_None = 0x0,
|
||||
OBJC_TQ_In = 0x1,
|
||||
OBJC_TQ_Inout = 0x2,
|
||||
OBJC_TQ_Out = 0x4,
|
||||
OBJC_TQ_Bycopy = 0x8,
|
||||
OBJC_TQ_Byref = 0x10,
|
||||
OBJC_TQ_Oneway = 0x20
|
||||
};
|
||||
|
||||
private:
|
||||
/// Loc - The location that this decl.
|
||||
SourceLocation Loc;
|
||||
|
||||
/// NextDeclarator - If this decl was part of a multi-declarator declaration,
|
||||
/// such as "int X, Y, *Z;" this indicates Decl for the next declarator.
|
||||
Decl *NextDeclarator;
|
||||
|
||||
/// NextDeclInScope - The next declaration within the same lexical
|
||||
/// DeclContext. These pointers form the linked list that is
|
||||
/// traversed via DeclContext's decls_begin()/decls_end().
|
||||
/// FIXME: If NextDeclarator is non-NULL, will it always be the same
|
||||
/// as NextDeclInScope? If so, we can use a
|
||||
/// PointerIntPair<Decl*, 1> to make Decl smaller.
|
||||
Decl *NextDeclInScope;
|
||||
|
||||
friend class DeclContext;
|
||||
|
||||
/// 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.
|
||||
/// For declarations with C++ scope specifiers, it contains a MultipleDC*
|
||||
/// with the context where it semantically belongs (SemanticDC) and the
|
||||
/// context where it was lexically declared (LexicalDC).
|
||||
/// e.g.:
|
||||
///
|
||||
/// namespace A {
|
||||
/// void f(); // SemanticDC == LexicalDC == 'namespace A'
|
||||
/// }
|
||||
/// void A::f(); // SemanticDC == namespace 'A'
|
||||
/// // LexicalDC == global namespace
|
||||
uintptr_t DeclCtx;
|
||||
|
||||
struct MultipleDC {
|
||||
DeclContext *SemanticDC;
|
||||
DeclContext *LexicalDC;
|
||||
};
|
||||
|
||||
inline bool isInSemaDC() const { return (DeclCtx & 0x1) == 0; }
|
||||
inline bool isOutOfSemaDC() const { return (DeclCtx & 0x1) != 0; }
|
||||
inline MultipleDC *getMultipleDC() const {
|
||||
return reinterpret_cast<MultipleDC*>(DeclCtx & ~0x1);
|
||||
}
|
||||
|
||||
/// DeclKind - This indicates which class this is.
|
||||
Kind DeclKind : 8;
|
||||
|
||||
/// InvalidDecl - This indicates a semantic error occurred.
|
||||
unsigned int InvalidDecl : 1;
|
||||
|
||||
/// HasAttrs - This indicates whether the decl has attributes or not.
|
||||
unsigned int HasAttrs : 1;
|
||||
|
||||
/// Implicit - Whether this declaration was implicitly generated by
|
||||
/// the implementation rather than explicitly written by the user.
|
||||
bool Implicit : 1;
|
||||
|
||||
protected:
|
||||
/// Access - Used by C++ decls for the access specifier.
|
||||
// NOTE: VC++ treats enums as signed, avoid using the AccessSpecifier enum
|
||||
unsigned Access : 2;
|
||||
friend class CXXClassMemberWrapper;
|
||||
|
||||
Decl(Kind DK, DeclContext *DC, SourceLocation L)
|
||||
: Loc(L), NextDeclarator(0), NextDeclInScope(0),
|
||||
DeclCtx(reinterpret_cast<uintptr_t>(DC)), DeclKind(DK), InvalidDecl(0),
|
||||
HasAttrs(false), Implicit(false) {
|
||||
if (Decl::CollectingStats()) addDeclKind(DK);
|
||||
}
|
||||
|
||||
virtual ~Decl();
|
||||
|
||||
/// setDeclContext - Set both the semantic and lexical DeclContext
|
||||
/// to DC.
|
||||
void setDeclContext(DeclContext *DC);
|
||||
|
||||
public:
|
||||
SourceLocation getLocation() const { return Loc; }
|
||||
void setLocation(SourceLocation L) { Loc = L; }
|
||||
|
||||
Kind getKind() const { return DeclKind; }
|
||||
const char *getDeclKindName() const;
|
||||
|
||||
const DeclContext *getDeclContext() const {
|
||||
if (isInSemaDC())
|
||||
return reinterpret_cast<DeclContext*>(DeclCtx);
|
||||
return getMultipleDC()->SemanticDC;
|
||||
}
|
||||
DeclContext *getDeclContext() {
|
||||
return const_cast<DeclContext*>(
|
||||
const_cast<const Decl*>(this)->getDeclContext());
|
||||
}
|
||||
|
||||
void setAccess(AccessSpecifier AS) { Access = AS; }
|
||||
AccessSpecifier getAccess() const { return AccessSpecifier(Access); }
|
||||
|
||||
void addAttr(Attr *attr);
|
||||
const Attr *getAttrs() const;
|
||||
void swapAttrs(Decl *D);
|
||||
void invalidateAttrs();
|
||||
|
||||
template<typename T> const T *getAttr() const {
|
||||
for (const Attr *attr = getAttrs(); attr; attr = attr->getNext())
|
||||
if (const T *V = dyn_cast<T>(attr))
|
||||
return V;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// setInvalidDecl - Indicates the Decl had a semantic error. This
|
||||
/// allows for graceful error recovery.
|
||||
void setInvalidDecl() { InvalidDecl = 1; }
|
||||
bool isInvalidDecl() const { return (bool) InvalidDecl; }
|
||||
|
||||
/// isImplicit - Indicates whether the declaration was implicitly
|
||||
/// generated by the implementation. If false, this declaration
|
||||
/// was written explicitly in the source code.
|
||||
bool isImplicit() const { return Implicit; }
|
||||
void setImplicit(bool I = true) { Implicit = I; }
|
||||
|
||||
IdentifierNamespace getIdentifierNamespace() const {
|
||||
switch (DeclKind) {
|
||||
default:
|
||||
if (DeclKind >= FunctionFirst && DeclKind <= FunctionLast)
|
||||
return IDNS_Ordinary;
|
||||
assert(0 && "Unknown decl kind!");
|
||||
case OverloadedFunction:
|
||||
case Typedef:
|
||||
case EnumConstant:
|
||||
case Var:
|
||||
case CXXClassVar:
|
||||
case ImplicitParam:
|
||||
case ParmVar:
|
||||
case OriginalParmVar:
|
||||
case NonTypeTemplateParm:
|
||||
case ObjCMethod:
|
||||
case ObjCContainer:
|
||||
case ObjCCategory:
|
||||
case ObjCProtocol:
|
||||
case ObjCInterface:
|
||||
case ObjCCategoryImpl:
|
||||
case ObjCProperty:
|
||||
case ObjCCompatibleAlias:
|
||||
return IDNS_Ordinary;
|
||||
|
||||
case Field:
|
||||
case ObjCAtDefsField:
|
||||
case ObjCIvar:
|
||||
return IDNS_Member;
|
||||
|
||||
case Record:
|
||||
case CXXRecord:
|
||||
case Enum:
|
||||
case TemplateTypeParm:
|
||||
return IDNS_Tag;
|
||||
|
||||
case Namespace:
|
||||
return IdentifierNamespace(IDNS_Tag | IDNS_Ordinary);
|
||||
}
|
||||
}
|
||||
|
||||
bool isInIdentifierNamespace(unsigned NS) const {
|
||||
return getIdentifierNamespace() & NS;
|
||||
}
|
||||
|
||||
/// getLexicalDeclContext - The declaration context where this Decl was
|
||||
/// lexically declared (LexicalDC). May be different from
|
||||
/// getDeclContext() (SemanticDC).
|
||||
/// e.g.:
|
||||
///
|
||||
/// namespace A {
|
||||
/// void f(); // SemanticDC == LexicalDC == 'namespace A'
|
||||
/// }
|
||||
/// void A::f(); // SemanticDC == namespace 'A'
|
||||
/// // LexicalDC == global namespace
|
||||
const DeclContext *getLexicalDeclContext() const {
|
||||
if (isInSemaDC())
|
||||
return reinterpret_cast<DeclContext*>(DeclCtx);
|
||||
return getMultipleDC()->LexicalDC;
|
||||
}
|
||||
DeclContext *getLexicalDeclContext() {
|
||||
return const_cast<DeclContext*>(
|
||||
const_cast<const Decl*>(this)->getLexicalDeclContext());
|
||||
}
|
||||
|
||||
void setLexicalDeclContext(DeclContext *DC);
|
||||
|
||||
/// getNextDeclarator - If this decl was part of a multi-declarator
|
||||
/// declaration, such as "int X, Y, *Z;" this returns the decl for the next
|
||||
/// declarator. Otherwise it returns null.
|
||||
Decl *getNextDeclarator() { return NextDeclarator; }
|
||||
const Decl *getNextDeclarator() const { return NextDeclarator; }
|
||||
void setNextDeclarator(Decl *N) { NextDeclarator = N; }
|
||||
|
||||
// isDefinedOutsideFunctionOrMethod - This predicate returns true if this
|
||||
// scoped decl is defined outside the current function or method. This is
|
||||
// roughly global variables and functions, but also handles enums (which could
|
||||
// be defined inside or outside a function etc).
|
||||
bool isDefinedOutsideFunctionOrMethod() const;
|
||||
|
||||
// getBody - If this Decl represents a declaration for a body of code,
|
||||
// such as a function or method definition, this method returns the top-level
|
||||
// Stmt* of that body. Otherwise this method returns null.
|
||||
virtual Stmt* getBody() const { return 0; }
|
||||
|
||||
// global temp stats (until we have a per-module visitor)
|
||||
static void addDeclKind(Kind k);
|
||||
static bool CollectingStats(bool Enable = false);
|
||||
static void PrintStats();
|
||||
|
||||
/// isTemplateParameter - Determines whether this declartion is a
|
||||
/// template parameter.
|
||||
bool isTemplateParameter() const;
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *) { return true; }
|
||||
static DeclContext *castToDeclContext(const Decl *);
|
||||
static Decl *castFromDeclContext(const DeclContext *);
|
||||
|
||||
/// Emit - Serialize this Decl to Bitcode.
|
||||
void Emit(llvm::Serializer& S) const;
|
||||
|
||||
/// Create - Deserialize a Decl from Bitcode.
|
||||
static Decl* Create(llvm::Deserializer& D, ASTContext& C);
|
||||
|
||||
/// Destroy - Call destructors and release memory.
|
||||
virtual void Destroy(ASTContext& C);
|
||||
|
||||
protected:
|
||||
/// EmitImpl - Provides the subclass-specific serialization logic for
|
||||
/// serializing out a decl.
|
||||
virtual void EmitImpl(llvm::Serializer& S) const {
|
||||
// FIXME: This will eventually be a pure virtual function.
|
||||
assert (false && "Not implemented.");
|
||||
}
|
||||
};
|
||||
|
||||
/// DeclContext - This is used only as base class of specific decl types that
|
||||
/// can act as declaration contexts. These decls are:
|
||||
///
|
||||
/// TranslationUnitDecl
|
||||
/// NamespaceDecl
|
||||
/// FunctionDecl
|
||||
/// RecordDecl/CXXRecordDecl
|
||||
/// EnumDecl
|
||||
/// ObjCMethodDecl
|
||||
/// ObjCInterfaceDecl
|
||||
/// LinkageSpecDecl
|
||||
/// BlockDecl
|
||||
class DeclContext {
|
||||
/// DeclKind - This indicates which class this is.
|
||||
Decl::Kind DeclKind : 8;
|
||||
|
||||
/// LookupPtrKind - Describes what kind of pointer LookupPtr
|
||||
/// actually is.
|
||||
enum LookupPtrKind {
|
||||
/// LookupIsMap - Indicates that LookupPtr is actually a map.
|
||||
LookupIsMap = 7
|
||||
};
|
||||
|
||||
/// LookupPtr - Pointer to a data structure used to lookup
|
||||
/// declarations within this context. If the context contains fewer
|
||||
/// than seven declarations, the number of declarations is provided
|
||||
/// in the 3 lowest-order bits and the upper bits are treated as a
|
||||
/// pointer to an array of NamedDecl pointers. If the context
|
||||
/// contains seven or more declarations, the upper bits are treated
|
||||
/// as a pointer to a DenseMap<DeclarationName, std::vector<NamedDecl*>>.
|
||||
/// FIXME: We need a better data structure for this.
|
||||
llvm::PointerIntPair<void*, 3> LookupPtr;
|
||||
|
||||
/// FirstDecl - The first declaration stored within this declaration
|
||||
/// context.
|
||||
Decl *FirstDecl;
|
||||
|
||||
/// 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.
|
||||
Decl *LastDecl;
|
||||
|
||||
// Used in the CastTo template to get the DeclKind
|
||||
// from a Decl or a DeclContext. DeclContext doesn't have a getKind() method
|
||||
// to avoid 'ambiguous access' compiler errors.
|
||||
template<typename T> struct KindTrait {
|
||||
static Decl::Kind getKind(const T *D) { return D->getKind(); }
|
||||
};
|
||||
|
||||
// Used only by the ToDecl and FromDecl methods
|
||||
template<typename To, typename From>
|
||||
static To *CastTo(const From *D) {
|
||||
Decl::Kind DK = KindTrait<From>::getKind(D);
|
||||
switch(DK) {
|
||||
case Decl::TranslationUnit:
|
||||
return static_cast<TranslationUnitDecl*>(const_cast<From*>(D));
|
||||
case Decl::Namespace:
|
||||
return static_cast<NamespaceDecl*>(const_cast<From*>(D));
|
||||
case Decl::Enum:
|
||||
return static_cast<EnumDecl*>(const_cast<From*>(D));
|
||||
case Decl::Record:
|
||||
return static_cast<RecordDecl*>(const_cast<From*>(D));
|
||||
case Decl::CXXRecord:
|
||||
return static_cast<CXXRecordDecl*>(const_cast<From*>(D));
|
||||
case Decl::ObjCMethod:
|
||||
return static_cast<ObjCMethodDecl*>(const_cast<From*>(D));
|
||||
case Decl::ObjCInterface:
|
||||
return static_cast<ObjCInterfaceDecl*>(const_cast<From*>(D));
|
||||
case Decl::ObjCCategory:
|
||||
return static_cast<ObjCCategoryDecl*>(const_cast<From*>(D));
|
||||
case Decl::ObjCProtocol:
|
||||
return static_cast<ObjCProtocolDecl*>(const_cast<From*>(D));
|
||||
case Decl::ObjCImplementation:
|
||||
return static_cast<ObjCImplementationDecl*>(const_cast<From*>(D));
|
||||
case Decl::ObjCCategoryImpl:
|
||||
return static_cast<ObjCCategoryImplDecl*>(const_cast<From*>(D));
|
||||
case Decl::LinkageSpec:
|
||||
return static_cast<LinkageSpecDecl*>(const_cast<From*>(D));
|
||||
case Decl::Block:
|
||||
return static_cast<BlockDecl*>(const_cast<From*>(D));
|
||||
default:
|
||||
if (DK >= Decl::FunctionFirst && DK <= Decl::FunctionLast)
|
||||
return static_cast<FunctionDecl*>(const_cast<From*>(D));
|
||||
|
||||
assert(false && "a decl that inherits DeclContext isn't handled");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// isLookupMap - Determine if the lookup structure is a
|
||||
/// DenseMap. Othewise, it is an array.
|
||||
bool isLookupMap() const { return LookupPtr.getInt() == LookupIsMap; }
|
||||
|
||||
static Decl *getNextDeclInScope(Decl *D) { return D->NextDeclInScope; }
|
||||
|
||||
protected:
|
||||
DeclContext(Decl::Kind K)
|
||||
: DeclKind(K), LookupPtr(), FirstDecl(0), LastDecl(0) { }
|
||||
|
||||
void DestroyDecls(ASTContext &C);
|
||||
|
||||
public:
|
||||
~DeclContext();
|
||||
|
||||
Decl::Kind getDeclKind() const {
|
||||
return DeclKind;
|
||||
}
|
||||
const char *getDeclKindName() const;
|
||||
|
||||
/// getParent - Returns the containing DeclContext if this is a Decl,
|
||||
/// else returns NULL.
|
||||
const DeclContext *getParent() const;
|
||||
DeclContext *getParent() {
|
||||
return const_cast<DeclContext*>(
|
||||
const_cast<const DeclContext*>(this)->getParent());
|
||||
}
|
||||
|
||||
/// getLexicalParent - Returns the containing lexical DeclContext. May be
|
||||
/// different from getParent, e.g.:
|
||||
///
|
||||
/// namespace A {
|
||||
/// struct S;
|
||||
/// }
|
||||
/// struct A::S {}; // getParent() == namespace 'A'
|
||||
/// // getLexicalParent() == translation unit
|
||||
///
|
||||
const DeclContext *getLexicalParent() const;
|
||||
DeclContext *getLexicalParent() {
|
||||
return const_cast<DeclContext*>(
|
||||
const_cast<const DeclContext*>(this)->getLexicalParent());
|
||||
}
|
||||
|
||||
bool isFunctionOrMethod() const {
|
||||
switch (DeclKind) {
|
||||
case Decl::Block:
|
||||
case Decl::ObjCMethod:
|
||||
return true;
|
||||
|
||||
default:
|
||||
if (DeclKind >= Decl::FunctionFirst && DeclKind <= Decl::FunctionLast)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool isFileContext() const {
|
||||
return DeclKind == Decl::TranslationUnit || DeclKind == Decl::Namespace;
|
||||
}
|
||||
|
||||
bool isRecord() const {
|
||||
return DeclKind == Decl::Record || DeclKind == Decl::CXXRecord;
|
||||
}
|
||||
|
||||
bool isNamespace() const {
|
||||
return DeclKind == Decl::Namespace;
|
||||
}
|
||||
|
||||
/// isTransparentContext - Determines whether this context is a
|
||||
/// "transparent" context, meaning that the members declared in this
|
||||
/// context are semantically declared in the nearest enclosing
|
||||
/// non-transparent (opaque) context but are lexically declared in
|
||||
/// this context. For example, consider the enumerators of an
|
||||
/// enumeration type:
|
||||
/// @code
|
||||
/// enum E {
|
||||
/// Val1
|
||||
/// };
|
||||
/// @endcode
|
||||
/// Here, E is a transparent context, so its enumerator (Val1) will
|
||||
/// appear (semantically) that it is in the same context of E.
|
||||
/// Examples of transparent contexts include: enumerations (except for
|
||||
/// C++0x scoped enums), C++ linkage specifications, and C++0x
|
||||
/// inline namespaces.
|
||||
bool isTransparentContext() const;
|
||||
|
||||
bool Encloses(DeclContext *DC) const {
|
||||
for (; DC; DC = DC->getParent())
|
||||
if (DC == this)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// getPrimaryContext - There may be many different
|
||||
/// declarations of the same entity (including forward declarations
|
||||
/// of classes, multiple definitions of namespaces, etc.), each with
|
||||
/// a different set of declarations. This routine returns the
|
||||
/// "primary" DeclContext structure, which will contain the
|
||||
/// information needed to perform name lookup into this context.
|
||||
DeclContext *getPrimaryContext();
|
||||
|
||||
/// getLookupContext - Retrieve the innermost non-transparent
|
||||
/// context of this context, which corresponds to the innermost
|
||||
/// location from which name lookup can find the entities in this
|
||||
/// context.
|
||||
DeclContext *getLookupContext() {
|
||||
return const_cast<DeclContext *>(
|
||||
const_cast<const DeclContext *>(this)->getLookupContext());
|
||||
}
|
||||
const DeclContext *getLookupContext() const;
|
||||
|
||||
/// getNextContext - If this is a DeclContext that may have other
|
||||
/// DeclContexts that are semantically connected but syntactically
|
||||
/// different, such as C++ namespaces, this routine retrieves the
|
||||
/// next DeclContext in the link. Iteration through the chain of
|
||||
/// DeclContexts should begin at the primary DeclContext and
|
||||
/// continue until this function returns NULL. For example, given:
|
||||
/// @code
|
||||
/// namespace N {
|
||||
/// int x;
|
||||
/// }
|
||||
/// namespace N {
|
||||
/// int y;
|
||||
/// }
|
||||
/// @endcode
|
||||
/// The first occurrence of namespace N will be the primary
|
||||
/// DeclContext. Its getNextContext will return the second
|
||||
/// occurrence of namespace N.
|
||||
DeclContext *getNextContext();
|
||||
|
||||
/// decl_iterator - Iterates through the declarations stored
|
||||
/// within this context.
|
||||
class decl_iterator {
|
||||
/// Current - The current declaration.
|
||||
Decl *Current;
|
||||
|
||||
public:
|
||||
typedef Decl* value_type;
|
||||
typedef Decl* reference;
|
||||
typedef Decl* pointer;
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
|
||||
decl_iterator() : Current(0) { }
|
||||
explicit decl_iterator(Decl *C) : Current(C) { }
|
||||
|
||||
reference operator*() const { return Current; }
|
||||
pointer operator->() const { return Current; }
|
||||
|
||||
decl_iterator& operator++();
|
||||
|
||||
decl_iterator operator++(int) {
|
||||
decl_iterator tmp(*this);
|
||||
++(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
/// decls_begin/decls_end - Iterate over the declarations stored in
|
||||
/// this context.
|
||||
decl_iterator decls_begin() const { return decl_iterator(FirstDecl); }
|
||||
decl_iterator decls_end() const { return decl_iterator(); }
|
||||
|
||||
/// specific_decl_iterator - Iterates over a subrange of
|
||||
/// declarations stored in a DeclContext, providing only those that
|
||||
/// are of type SpecificDecl (or a class derived from it). This
|
||||
/// iterator is used, for example, to provide iteration over just
|
||||
/// the fields within a RecordDecl (with SpecificDecl = FieldDecl).
|
||||
template<typename SpecificDecl>
|
||||
class specific_decl_iterator {
|
||||
/// Current - The current, underlying declaration iterator, which
|
||||
/// will either be NULL or will point to a declaration of
|
||||
/// type SpecificDecl.
|
||||
DeclContext::decl_iterator Current;
|
||||
|
||||
/// SkipToNextDecl - Advances the current position up to the next
|
||||
/// declaration of type SpecificDecl that also meets the criteria
|
||||
/// required by Acceptable.
|
||||
void SkipToNextDecl() {
|
||||
while (*Current && !isa<SpecificDecl>(*Current))
|
||||
++Current;
|
||||
}
|
||||
|
||||
public:
|
||||
typedef SpecificDecl* value_type;
|
||||
typedef SpecificDecl* reference;
|
||||
typedef SpecificDecl* pointer;
|
||||
typedef std::iterator_traits<DeclContext::decl_iterator>::difference_type
|
||||
difference_type;
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
|
||||
specific_decl_iterator() : Current() { }
|
||||
|
||||
/// specific_decl_iterator - Construct a new iterator over a
|
||||
/// subset of the declarations the range [C,
|
||||
/// end-of-declarations). If A is non-NULL, it is a pointer to a
|
||||
/// member function of SpecificDecl that should return true for
|
||||
/// all of the SpecificDecl instances that will be in the subset
|
||||
/// of iterators. For example, if you want Objective-C instance
|
||||
/// methods, SpecificDecl will be ObjCMethodDecl and A will be
|
||||
/// &ObjCMethodDecl::isInstanceMethod.
|
||||
explicit specific_decl_iterator(DeclContext::decl_iterator C) : Current(C) {
|
||||
SkipToNextDecl();
|
||||
}
|
||||
|
||||
reference operator*() const { return cast<SpecificDecl>(*Current); }
|
||||
pointer operator->() const { return cast<SpecificDecl>(*Current); }
|
||||
|
||||
specific_decl_iterator& operator++() {
|
||||
++Current;
|
||||
SkipToNextDecl();
|
||||
return *this;
|
||||
}
|
||||
|
||||
specific_decl_iterator operator++(int) {
|
||||
specific_decl_iterator tmp(*this);
|
||||
++(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
friend bool
|
||||
operator==(const specific_decl_iterator& x, const specific_decl_iterator& y) {
|
||||
return x.Current == y.Current;
|
||||
}
|
||||
|
||||
friend bool
|
||||
operator!=(const specific_decl_iterator& x, const specific_decl_iterator& y) {
|
||||
return x.Current != y.Current;
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief Iterates over a filtered subrange of declarations stored
|
||||
/// in a DeclContext.
|
||||
///
|
||||
/// This iterator visits only those declarations that are of type
|
||||
/// SpecificDecl (or a class derived from it) and that meet some
|
||||
/// additional run-time criteria. This iterator is used, for
|
||||
/// example, to provide access to the instance methods within an
|
||||
/// Objective-C interface (with SpecificDecl = ObjCMethodDecl and
|
||||
/// Acceptable = ObjCMethodDecl::isInstanceMethod).
|
||||
template<typename SpecificDecl, bool (SpecificDecl::*Acceptable)() const>
|
||||
class filtered_decl_iterator {
|
||||
/// Current - The current, underlying declaration iterator, which
|
||||
/// will either be NULL or will point to a declaration of
|
||||
/// type SpecificDecl.
|
||||
DeclContext::decl_iterator Current;
|
||||
|
||||
/// SkipToNextDecl - Advances the current position up to the next
|
||||
/// declaration of type SpecificDecl that also meets the criteria
|
||||
/// required by Acceptable.
|
||||
void SkipToNextDecl() {
|
||||
while (*Current &&
|
||||
(!isa<SpecificDecl>(*Current) ||
|
||||
(Acceptable && !(cast<SpecificDecl>(*Current)->*Acceptable)())))
|
||||
++Current;
|
||||
}
|
||||
|
||||
public:
|
||||
typedef SpecificDecl* value_type;
|
||||
typedef SpecificDecl* reference;
|
||||
typedef SpecificDecl* pointer;
|
||||
typedef std::iterator_traits<DeclContext::decl_iterator>::difference_type
|
||||
difference_type;
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
|
||||
filtered_decl_iterator() : Current() { }
|
||||
|
||||
/// specific_decl_iterator - Construct a new iterator over a
|
||||
/// subset of the declarations the range [C,
|
||||
/// end-of-declarations). If A is non-NULL, it is a pointer to a
|
||||
/// member function of SpecificDecl that should return true for
|
||||
/// all of the SpecificDecl instances that will be in the subset
|
||||
/// of iterators. For example, if you want Objective-C instance
|
||||
/// methods, SpecificDecl will be ObjCMethodDecl and A will be
|
||||
/// &ObjCMethodDecl::isInstanceMethod.
|
||||
explicit filtered_decl_iterator(DeclContext::decl_iterator C) : Current(C) {
|
||||
SkipToNextDecl();
|
||||
}
|
||||
|
||||
reference operator*() const { return cast<SpecificDecl>(*Current); }
|
||||
pointer operator->() const { return cast<SpecificDecl>(*Current); }
|
||||
|
||||
filtered_decl_iterator& operator++() {
|
||||
++Current;
|
||||
SkipToNextDecl();
|
||||
return *this;
|
||||
}
|
||||
|
||||
filtered_decl_iterator operator++(int) {
|
||||
filtered_decl_iterator tmp(*this);
|
||||
++(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
friend bool
|
||||
operator==(const filtered_decl_iterator& x, const filtered_decl_iterator& y) {
|
||||
return x.Current == y.Current;
|
||||
}
|
||||
|
||||
friend bool
|
||||
operator!=(const filtered_decl_iterator& x, const filtered_decl_iterator& y) {
|
||||
return x.Current != y.Current;
|
||||
}
|
||||
};
|
||||
|
||||
/// @brief Add the declaration D into this context.
|
||||
///
|
||||
/// This routine should be invoked when the declaration D has first
|
||||
/// been declared, to place D into the context where it was
|
||||
/// (lexically) defined. Every declaration must be added to one
|
||||
/// (and only one!) context, where it can be visited via
|
||||
/// [decls_begin(), decls_end()). Once a declaration has been added
|
||||
/// to its lexical context, the corresponding DeclContext owns the
|
||||
/// declaration.
|
||||
///
|
||||
/// If D is also a NamedDecl, it will be made visible within its
|
||||
/// semantic context via makeDeclVisibleInContext.
|
||||
void addDecl(Decl *D);
|
||||
|
||||
/// lookup_iterator - An iterator that provides access to the results
|
||||
/// of looking up a name within this context.
|
||||
typedef NamedDecl **lookup_iterator;
|
||||
|
||||
/// lookup_const_iterator - An iterator that provides non-mutable
|
||||
/// access to the results of lookup up a name within this context.
|
||||
typedef NamedDecl * const * lookup_const_iterator;
|
||||
|
||||
typedef std::pair<lookup_iterator, lookup_iterator> lookup_result;
|
||||
typedef std::pair<lookup_const_iterator, lookup_const_iterator>
|
||||
lookup_const_result;
|
||||
|
||||
/// lookup - Find the declarations (if any) with the given Name in
|
||||
/// this context. Returns a range of iterators that contains all of
|
||||
/// the declarations with this name, with object, function, member,
|
||||
/// and enumerator names preceding any tag name. Note that this
|
||||
/// routine will not look into parent contexts.
|
||||
lookup_result lookup(DeclarationName Name);
|
||||
lookup_const_result lookup(DeclarationName Name) const;
|
||||
|
||||
/// @brief Makes a declaration visible within this context.
|
||||
///
|
||||
/// This routine makes the declaration D visible to name lookup
|
||||
/// within this context and, if this is a transparent context,
|
||||
/// within its parent contexts up to the first enclosing
|
||||
/// non-transparent context. Making a declaration visible within a
|
||||
/// context does not transfer ownership of a declaration, and a
|
||||
/// declaration can be visible in many contexts that aren't its
|
||||
/// lexical context.
|
||||
///
|
||||
/// If D is a redeclaration of an existing declaration that is
|
||||
/// visible from this context, as determined by
|
||||
/// NamedDecl::declarationReplaces, the previous declaration will be
|
||||
/// replaced with D.
|
||||
void makeDeclVisibleInContext(NamedDecl *D);
|
||||
|
||||
static bool classof(const Decl *D) {
|
||||
switch (D->getKind()) {
|
||||
#define DECL_CONTEXT(Name) case Decl::Name:
|
||||
#include "clang/AST/DeclNodes.def"
|
||||
return true;
|
||||
default:
|
||||
if (D->getKind() >= Decl::FunctionFirst &&
|
||||
D->getKind() <= Decl::FunctionLast)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
static bool classof(const DeclContext *D) { return true; }
|
||||
#define DECL_CONTEXT(Name) \
|
||||
static bool classof(const Name##Decl *D) { return true; }
|
||||
#include "clang/AST/DeclNodes.def"
|
||||
|
||||
private:
|
||||
void buildLookup(DeclContext *DCtx);
|
||||
void makeDeclVisibleInContextImpl(NamedDecl *D);
|
||||
|
||||
void EmitOutRec(llvm::Serializer& S) const;
|
||||
void ReadOutRec(llvm::Deserializer& D, ASTContext& C);
|
||||
|
||||
friend class Decl;
|
||||
};
|
||||
|
||||
template<> struct DeclContext::KindTrait<DeclContext> {
|
||||
static Decl::Kind getKind(const DeclContext *D) { return D->DeclKind; }
|
||||
};
|
||||
|
||||
inline bool Decl::isTemplateParameter() const {
|
||||
return getKind() == TemplateTypeParm || getKind() == NonTypeTemplateParm;
|
||||
}
|
||||
|
||||
inline bool Decl::isDefinedOutsideFunctionOrMethod() const {
|
||||
if (getDeclContext())
|
||||
return !getDeclContext()->getLookupContext()->isFunctionOrMethod();
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
inline DeclContext::decl_iterator& DeclContext::decl_iterator::operator++() {
|
||||
Current = getNextDeclInScope(Current);
|
||||
return *this;
|
||||
}
|
||||
|
||||
} // end clang.
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/// Implement a isa_impl_wrap specialization to check whether a DeclContext is
|
||||
/// a specific Decl.
|
||||
template<class ToTy>
|
||||
struct isa_impl_wrap<ToTy,
|
||||
const ::clang::DeclContext,const ::clang::DeclContext> {
|
||||
static bool doit(const ::clang::DeclContext &Val) {
|
||||
return ToTy::classof(::clang::Decl::castFromDeclContext(&Val));
|
||||
}
|
||||
};
|
||||
template<class ToTy>
|
||||
struct isa_impl_wrap<ToTy, ::clang::DeclContext, ::clang::DeclContext>
|
||||
: public isa_impl_wrap<ToTy,
|
||||
const ::clang::DeclContext,const ::clang::DeclContext> {};
|
||||
|
||||
/// Implement cast_convert_val for Decl -> DeclContext conversions.
|
||||
template<class FromTy>
|
||||
struct cast_convert_val< ::clang::DeclContext, FromTy, FromTy> {
|
||||
static ::clang::DeclContext &doit(const FromTy &Val) {
|
||||
return *FromTy::castToDeclContext(&Val);
|
||||
}
|
||||
};
|
||||
|
||||
template<class FromTy>
|
||||
struct cast_convert_val< ::clang::DeclContext, FromTy*, FromTy*> {
|
||||
static ::clang::DeclContext *doit(const FromTy *Val) {
|
||||
return FromTy::castToDeclContext(Val);
|
||||
}
|
||||
};
|
||||
|
||||
template<class FromTy>
|
||||
struct cast_convert_val< const ::clang::DeclContext, FromTy, FromTy> {
|
||||
static const ::clang::DeclContext &doit(const FromTy &Val) {
|
||||
return *FromTy::castToDeclContext(&Val);
|
||||
}
|
||||
};
|
||||
|
||||
template<class FromTy>
|
||||
struct cast_convert_val< const ::clang::DeclContext, FromTy*, FromTy*> {
|
||||
static const ::clang::DeclContext *doit(const FromTy *Val) {
|
||||
return FromTy::castToDeclContext(Val);
|
||||
}
|
||||
};
|
||||
|
||||
/// Implement cast_convert_val for DeclContext -> Decl conversions.
|
||||
template<class ToTy>
|
||||
struct cast_convert_val<ToTy,
|
||||
const ::clang::DeclContext,const ::clang::DeclContext> {
|
||||
static ToTy &doit(const ::clang::DeclContext &Val) {
|
||||
return *reinterpret_cast<ToTy*>(ToTy::castFromDeclContext(&Val));
|
||||
}
|
||||
};
|
||||
template<class ToTy>
|
||||
struct cast_convert_val<ToTy, ::clang::DeclContext, ::clang::DeclContext>
|
||||
: public cast_convert_val<ToTy,
|
||||
const ::clang::DeclContext,const ::clang::DeclContext> {};
|
||||
|
||||
template<class ToTy>
|
||||
struct cast_convert_val<ToTy,
|
||||
const ::clang::DeclContext*, const ::clang::DeclContext*> {
|
||||
static ToTy *doit(const ::clang::DeclContext *Val) {
|
||||
return reinterpret_cast<ToTy*>(ToTy::castFromDeclContext(Val));
|
||||
}
|
||||
};
|
||||
template<class ToTy>
|
||||
struct cast_convert_val<ToTy, ::clang::DeclContext*, ::clang::DeclContext*>
|
||||
: public cast_convert_val<ToTy,
|
||||
const ::clang::DeclContext*,const ::clang::DeclContext*> {};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
||||
@@ -1,981 +0,0 @@
|
||||
//===-- DeclCXX.h - Classes for representing C++ declarations -*- 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 C++ Decl subclasses.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_DECLCXX_H
|
||||
#define LLVM_CLANG_AST_DECLCXX_H
|
||||
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
|
||||
namespace clang {
|
||||
class CXXRecordDecl;
|
||||
class CXXConstructorDecl;
|
||||
class CXXDestructorDecl;
|
||||
class CXXConversionDecl;
|
||||
class CXXMethodDecl;
|
||||
|
||||
/// TemplateTypeParmDecl - Declaration of a template type parameter,
|
||||
/// e.g., "T" in
|
||||
/// @code
|
||||
/// template<typename T> class vector;
|
||||
/// @endcode
|
||||
class TemplateTypeParmDecl : public TypeDecl {
|
||||
/// Typename - Whether this template type parameter was declaration
|
||||
/// with the 'typename' keyword. If false, it was declared with the
|
||||
/// 'class' keyword.
|
||||
bool Typename : 1;
|
||||
|
||||
TemplateTypeParmDecl(DeclContext *DC, SourceLocation L,
|
||||
IdentifierInfo *Id, bool Typename)
|
||||
: TypeDecl(TemplateTypeParm, DC, L, Id), Typename(Typename) { }
|
||||
|
||||
public:
|
||||
static TemplateTypeParmDecl *Create(ASTContext &C, DeclContext *DC,
|
||||
SourceLocation L, IdentifierInfo *Id,
|
||||
bool Typename);
|
||||
|
||||
/// wasDeclarationWithTypename - Whether this template type
|
||||
/// parameter was declared with the 'typename' keyword. If not, it
|
||||
/// was declared with the 'class' keyword.
|
||||
bool wasDeclaredWithTypename() const { return Typename; }
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) {
|
||||
return D->getKind() == TemplateTypeParm;
|
||||
}
|
||||
static bool classof(const TemplateTypeParmDecl *D) { return true; }
|
||||
|
||||
protected:
|
||||
/// EmitImpl - Serialize this TemplateTypeParmDecl. Called by Decl::Emit.
|
||||
virtual void EmitImpl(llvm::Serializer& S) const;
|
||||
|
||||
/// CreateImpl - Deserialize a TemplateTypeParmDecl. Called by Decl::Create.
|
||||
static TemplateTypeParmDecl* CreateImpl(llvm::Deserializer& D, ASTContext& C);
|
||||
|
||||
friend Decl* Decl::Create(llvm::Deserializer& D, ASTContext& C);
|
||||
};
|
||||
|
||||
/// NonTypeTemplateParmDecl - Declares a non-type template parameter,
|
||||
/// e.g., "Size" in
|
||||
/// @code
|
||||
/// template<int Size> class array { };
|
||||
/// @endcode
|
||||
class NonTypeTemplateParmDecl : public VarDecl {
|
||||
NonTypeTemplateParmDecl(DeclContext *DC, SourceLocation L,
|
||||
IdentifierInfo *Id, QualType T,
|
||||
SourceLocation TSSL = SourceLocation())
|
||||
: VarDecl(NonTypeTemplateParm, DC, L, Id, T, VarDecl::None, TSSL) { }
|
||||
|
||||
public:
|
||||
static NonTypeTemplateParmDecl *
|
||||
Create(ASTContext &C, DeclContext *DC, SourceLocation L, IdentifierInfo *Id,
|
||||
QualType T, SourceLocation TypeSpecStartLoc = SourceLocation());
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) {
|
||||
return D->getKind() == NonTypeTemplateParm;
|
||||
}
|
||||
static bool classof(const NonTypeTemplateParmDecl *D) { return true; }
|
||||
};
|
||||
|
||||
/// OverloadedFunctionDecl - An instance of this class represents a
|
||||
/// set of overloaded functions. All of the functions have the same
|
||||
/// name and occur within the same scope.
|
||||
///
|
||||
/// An OverloadedFunctionDecl has no ownership over the FunctionDecl
|
||||
/// nodes it contains. Rather, the FunctionDecls are owned by the
|
||||
/// enclosing scope (which also owns the OverloadedFunctionDecl
|
||||
/// node). OverloadedFunctionDecl is used primarily to store a set of
|
||||
/// overloaded functions for name lookup.
|
||||
class OverloadedFunctionDecl : public NamedDecl {
|
||||
protected:
|
||||
OverloadedFunctionDecl(DeclContext *DC, DeclarationName N)
|
||||
: NamedDecl(OverloadedFunction, DC, SourceLocation(), N) { }
|
||||
|
||||
/// Functions - the set of overloaded functions contained in this
|
||||
/// overload set.
|
||||
llvm::SmallVector<FunctionDecl *, 4> Functions;
|
||||
|
||||
public:
|
||||
typedef llvm::SmallVector<FunctionDecl *, 4>::iterator function_iterator;
|
||||
typedef llvm::SmallVector<FunctionDecl *, 4>::const_iterator
|
||||
function_const_iterator;
|
||||
|
||||
static OverloadedFunctionDecl *Create(ASTContext &C, DeclContext *DC,
|
||||
DeclarationName N);
|
||||
|
||||
/// addOverload - Add an overloaded function FD to this set of
|
||||
/// overloaded functions.
|
||||
void addOverload(FunctionDecl *FD) {
|
||||
assert((FD->getDeclName() == getDeclName() ||
|
||||
isa<CXXConversionDecl>(FD) || isa<CXXConstructorDecl>(FD)) &&
|
||||
"Overloaded functions must have the same name");
|
||||
Functions.push_back(FD);
|
||||
|
||||
// An overloaded function declaration always has the location of
|
||||
// the most-recently-added function declaration.
|
||||
if (FD->getLocation().isValid())
|
||||
this->setLocation(FD->getLocation());
|
||||
}
|
||||
|
||||
function_iterator function_begin() { return Functions.begin(); }
|
||||
function_iterator function_end() { return Functions.end(); }
|
||||
function_const_iterator function_begin() const { return Functions.begin(); }
|
||||
function_const_iterator function_end() const { return Functions.end(); }
|
||||
|
||||
/// getNumFunctions - the number of overloaded functions stored in
|
||||
/// this set.
|
||||
unsigned getNumFunctions() const { return Functions.size(); }
|
||||
|
||||
/// getFunction - retrieve the ith function in the overload set.
|
||||
const FunctionDecl *getFunction(unsigned i) const {
|
||||
assert(i < getNumFunctions() && "Illegal function #");
|
||||
return Functions[i];
|
||||
}
|
||||
FunctionDecl *getFunction(unsigned i) {
|
||||
assert(i < getNumFunctions() && "Illegal function #");
|
||||
return Functions[i];
|
||||
}
|
||||
|
||||
// getDeclContext - Get the context of these overloaded functions.
|
||||
DeclContext *getDeclContext() {
|
||||
assert(getNumFunctions() > 0 && "Context of an empty overload set");
|
||||
return getFunction(0)->getDeclContext();
|
||||
}
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) {
|
||||
return D->getKind() == OverloadedFunction;
|
||||
}
|
||||
static bool classof(const OverloadedFunctionDecl *D) { return true; }
|
||||
|
||||
protected:
|
||||
/// EmitImpl - Serialize this FunctionDecl. Called by Decl::Emit.
|
||||
virtual void EmitImpl(llvm::Serializer& S) const;
|
||||
|
||||
/// CreateImpl - Deserialize an OverloadedFunctionDecl. Called by
|
||||
/// Decl::Create.
|
||||
static OverloadedFunctionDecl* CreateImpl(llvm::Deserializer& D,
|
||||
ASTContext& C);
|
||||
|
||||
friend Decl* Decl::Create(llvm::Deserializer& D, ASTContext& C);
|
||||
friend class CXXRecordDecl;
|
||||
};
|
||||
|
||||
/// CXXBaseSpecifier - A base class of a C++ class.
|
||||
///
|
||||
/// Each CXXBaseSpecifier represents a single, direct base class (or
|
||||
/// struct) of a C++ class (or struct). It specifies the type of that
|
||||
/// base class, whether it is a virtual or non-virtual base, and what
|
||||
/// level of access (public, protected, private) is used for the
|
||||
/// derivation. For example:
|
||||
///
|
||||
/// @code
|
||||
/// class A { };
|
||||
/// class B { };
|
||||
/// class C : public virtual A, protected B { };
|
||||
/// @endcode
|
||||
///
|
||||
/// In this code, C will have two CXXBaseSpecifiers, one for "public
|
||||
/// virtual A" and the other for "protected B".
|
||||
class CXXBaseSpecifier {
|
||||
/// Range - The source code range that covers the full base
|
||||
/// specifier, including the "virtual" (if present) and access
|
||||
/// specifier (if present).
|
||||
SourceRange Range;
|
||||
|
||||
/// Virtual - Whether this is a virtual base class or not.
|
||||
bool Virtual : 1;
|
||||
|
||||
/// BaseOfClass - Whether this is the base of a class (true) or of a
|
||||
/// struct (false). This determines the mapping from the access
|
||||
/// specifier as written in the source code to the access specifier
|
||||
/// used for semantic analysis.
|
||||
bool BaseOfClass : 1;
|
||||
|
||||
/// Access - Access specifier as written in the source code (which
|
||||
/// may be AS_none). The actual type of data stored here is an
|
||||
/// AccessSpecifier, but we use "unsigned" here to work around a
|
||||
/// VC++ bug.
|
||||
unsigned Access : 2;
|
||||
|
||||
/// BaseType - The type of the base class. This will be a class or
|
||||
/// struct (or a typedef of such).
|
||||
QualType BaseType;
|
||||
|
||||
public:
|
||||
CXXBaseSpecifier() { }
|
||||
|
||||
CXXBaseSpecifier(SourceRange R, bool V, bool BC, AccessSpecifier A, QualType T)
|
||||
: Range(R), Virtual(V), BaseOfClass(BC), Access(A), BaseType(T) { }
|
||||
|
||||
/// getSourceRange - Retrieves the source range that contains the
|
||||
/// entire base specifier.
|
||||
SourceRange getSourceRange() const { return Range; }
|
||||
|
||||
/// isVirtual - Determines whether the base class is a virtual base
|
||||
/// class (or not).
|
||||
bool isVirtual() const { return Virtual; }
|
||||
|
||||
/// getAccessSpecifier - Returns the access specifier for this base
|
||||
/// specifier. This is the actual base specifier as used for
|
||||
/// semantic analysis, so the result can never be AS_none. To
|
||||
/// retrieve the access specifier as written in the source code, use
|
||||
/// getAccessSpecifierAsWritten().
|
||||
AccessSpecifier getAccessSpecifier() const {
|
||||
if ((AccessSpecifier)Access == AS_none)
|
||||
return BaseOfClass? AS_private : AS_public;
|
||||
else
|
||||
return (AccessSpecifier)Access;
|
||||
}
|
||||
|
||||
/// getAccessSpecifierAsWritten - Retrieves the access specifier as
|
||||
/// written in the source code (which may mean that no access
|
||||
/// specifier was explicitly written). Use getAccessSpecifier() to
|
||||
/// retrieve the access specifier for use in semantic analysis.
|
||||
AccessSpecifier getAccessSpecifierAsWritten() const {
|
||||
return (AccessSpecifier)Access;
|
||||
}
|
||||
|
||||
/// getType - Retrieves the type of the base class. This type will
|
||||
/// always be an unqualified class type.
|
||||
QualType getType() const { return BaseType; }
|
||||
};
|
||||
|
||||
/// CXXRecordDecl - Represents a C++ struct/union/class.
|
||||
/// FIXME: This class will disappear once we've properly taught RecordDecl
|
||||
/// to deal with C++-specific things.
|
||||
class CXXRecordDecl : public RecordDecl {
|
||||
/// UserDeclaredConstructor - True when this class has a
|
||||
/// user-declared constructor.
|
||||
bool UserDeclaredConstructor : 1;
|
||||
|
||||
/// UserDeclaredCopyConstructor - True when this class has a
|
||||
/// user-declared copy constructor.
|
||||
bool UserDeclaredCopyConstructor : 1;
|
||||
|
||||
/// UserDeclaredCopyAssignment - True when this class has a
|
||||
/// user-declared copy assignment operator.
|
||||
bool UserDeclaredCopyAssignment : 1;
|
||||
|
||||
/// UserDeclaredDestructor - True when this class has a
|
||||
/// user-declared destructor.
|
||||
bool UserDeclaredDestructor : 1;
|
||||
|
||||
/// Aggregate - True when this class is an aggregate.
|
||||
bool Aggregate : 1;
|
||||
|
||||
/// PlainOldData - True when this class is a POD-type.
|
||||
bool PlainOldData : 1;
|
||||
|
||||
/// Polymorphic - True when this class is polymorphic, i.e. has at least one
|
||||
/// virtual member or derives from a polymorphic class.
|
||||
bool Polymorphic : 1;
|
||||
|
||||
/// Bases - Base classes of this class.
|
||||
/// FIXME: This is wasted space for a union.
|
||||
CXXBaseSpecifier *Bases;
|
||||
|
||||
/// NumBases - The number of base class specifiers in Bases.
|
||||
unsigned NumBases;
|
||||
|
||||
/// Conversions - Overload set containing the conversion functions
|
||||
/// of this C++ class (but not its inherited conversion
|
||||
/// functions). Each of the entries in this overload set is a
|
||||
/// CXXConversionDecl.
|
||||
OverloadedFunctionDecl Conversions;
|
||||
|
||||
CXXRecordDecl(TagKind TK, DeclContext *DC,
|
||||
SourceLocation L, IdentifierInfo *Id);
|
||||
|
||||
~CXXRecordDecl();
|
||||
|
||||
public:
|
||||
/// base_class_iterator - Iterator that traverses the base classes
|
||||
/// of a clas.
|
||||
typedef CXXBaseSpecifier* base_class_iterator;
|
||||
|
||||
/// base_class_const_iterator - Iterator that traverses the base
|
||||
/// classes of a clas.
|
||||
typedef const CXXBaseSpecifier* base_class_const_iterator;
|
||||
|
||||
static CXXRecordDecl *Create(ASTContext &C, TagKind TK, DeclContext *DC,
|
||||
SourceLocation L, IdentifierInfo *Id,
|
||||
CXXRecordDecl* PrevDecl=0);
|
||||
|
||||
/// setBases - Sets the base classes of this struct or class.
|
||||
void setBases(CXXBaseSpecifier const * const *Bases, unsigned NumBases);
|
||||
|
||||
/// getNumBases - Retrieves the number of base classes of this
|
||||
/// class.
|
||||
unsigned getNumBases() const { return NumBases; }
|
||||
|
||||
base_class_iterator bases_begin() { return Bases; }
|
||||
base_class_const_iterator bases_begin() const { return Bases; }
|
||||
base_class_iterator bases_end() { return Bases + NumBases; }
|
||||
base_class_const_iterator bases_end() const { return Bases + NumBases; }
|
||||
|
||||
/// hasConstCopyConstructor - Determines whether this class has a
|
||||
/// copy constructor that accepts a const-qualified argument.
|
||||
bool hasConstCopyConstructor(ASTContext &Context) const;
|
||||
|
||||
/// hasConstCopyAssignment - Determines whether this class has a
|
||||
/// copy assignment operator that accepts a const-qualified argument.
|
||||
bool hasConstCopyAssignment(ASTContext &Context) const;
|
||||
|
||||
/// addedConstructor - Notify the class that another constructor has
|
||||
/// been added. This routine helps maintain information about the
|
||||
/// class based on which constructors have been added.
|
||||
void addedConstructor(ASTContext &Context, CXXConstructorDecl *ConDecl);
|
||||
|
||||
/// hasUserDeclaredConstructor - Whether this class has any
|
||||
/// user-declared constructors. When true, a default constructor
|
||||
/// will not be implicitly declared.
|
||||
bool hasUserDeclaredConstructor() const { return UserDeclaredConstructor; }
|
||||
|
||||
/// hasUserDeclaredCopyConstructor - Whether this class has a
|
||||
/// user-declared copy constructor. When false, a copy constructor
|
||||
/// will be implicitly declared.
|
||||
bool hasUserDeclaredCopyConstructor() const {
|
||||
return UserDeclaredCopyConstructor;
|
||||
}
|
||||
|
||||
/// addedAssignmentOperator - Notify the class that another assignment
|
||||
/// operator has been added. This routine helps maintain information about the
|
||||
/// class based on which operators have been added.
|
||||
void addedAssignmentOperator(ASTContext &Context, CXXMethodDecl *OpDecl);
|
||||
|
||||
/// hasUserDeclaredCopyAssignment - Whether this class has a
|
||||
/// user-declared copy assignment operator. When false, a copy
|
||||
/// assigment operator will be implicitly declared.
|
||||
bool hasUserDeclaredCopyAssignment() const {
|
||||
return UserDeclaredCopyAssignment;
|
||||
}
|
||||
|
||||
/// hasUserDeclaredDestructor - Whether this class has a
|
||||
/// user-declared destructor. When false, a destructor will be
|
||||
/// implicitly declared.
|
||||
bool hasUserDeclaredDestructor() const { return UserDeclaredDestructor; }
|
||||
|
||||
/// setUserDeclaredDestructor - Set whether this class has a
|
||||
/// user-declared destructor. If not set by the time the class is
|
||||
/// fully defined, a destructor will be implicitly declared.
|
||||
void setUserDeclaredDestructor(bool UCD = true) {
|
||||
UserDeclaredDestructor = UCD;
|
||||
}
|
||||
|
||||
/// getConversions - Retrieve the overload set containing all of the
|
||||
/// conversion functions in this class.
|
||||
OverloadedFunctionDecl *getConversionFunctions() {
|
||||
return &Conversions;
|
||||
}
|
||||
const OverloadedFunctionDecl *getConversionFunctions() const {
|
||||
return &Conversions;
|
||||
}
|
||||
|
||||
/// addConversionFunction - Add a new conversion function to the
|
||||
/// list of conversion functions.
|
||||
void addConversionFunction(ASTContext &Context, CXXConversionDecl *ConvDecl);
|
||||
|
||||
/// isAggregate - Whether this class is an aggregate (C++
|
||||
/// [dcl.init.aggr]), which is a class with no user-declared
|
||||
/// constructors, no private or protected non-static data members,
|
||||
/// no base classes, and no virtual functions (C++ [dcl.init.aggr]p1).
|
||||
bool isAggregate() const { return Aggregate; }
|
||||
|
||||
/// setAggregate - Set whether this class is an aggregate (C++
|
||||
/// [dcl.init.aggr]).
|
||||
void setAggregate(bool Agg) { Aggregate = Agg; }
|
||||
|
||||
/// isPOD - Whether this class is a POD-type (C++ [class]p4), which is a class
|
||||
/// that is an aggregate that has no non-static non-POD data members, no
|
||||
/// reference data members, no user-defined copy assignment operator and no
|
||||
/// user-defined destructor.
|
||||
bool isPOD() const { return PlainOldData; }
|
||||
|
||||
/// setPOD - Set whether this class is a POD-type (C++ [class]p4).
|
||||
void setPOD(bool POD) { PlainOldData = POD; }
|
||||
|
||||
/// isPolymorphic - Whether this class is polymorphic (C++ [class.virtual]),
|
||||
/// which means that the class contains or inherits a virtual function.
|
||||
bool isPolymorphic() const { return Polymorphic; }
|
||||
|
||||
/// setPolymorphic - Set whether this class is polymorphic (C++
|
||||
/// [class.virtual]).
|
||||
void setPolymorphic(bool Poly) { Polymorphic = Poly; }
|
||||
|
||||
/// viewInheritance - Renders and displays an inheritance diagram
|
||||
/// for this C++ class and all of its base classes (transitively) using
|
||||
/// GraphViz.
|
||||
void viewInheritance(ASTContext& Context) const;
|
||||
|
||||
static bool classof(const Decl *D) { return D->getKind() == CXXRecord; }
|
||||
static bool classof(const CXXRecordDecl *D) { return true; }
|
||||
static DeclContext *castToDeclContext(const CXXRecordDecl *D) {
|
||||
return static_cast<DeclContext *>(const_cast<CXXRecordDecl*>(D));
|
||||
}
|
||||
static CXXRecordDecl *castFromDeclContext(const DeclContext *DC) {
|
||||
return static_cast<CXXRecordDecl *>(const_cast<DeclContext*>(DC));
|
||||
}
|
||||
|
||||
protected:
|
||||
/// EmitImpl - Serialize this CXXRecordDecl. Called by Decl::Emit.
|
||||
// FIXME: Implement this.
|
||||
//virtual void EmitImpl(llvm::Serializer& S) const;
|
||||
|
||||
/// CreateImpl - Deserialize a CXXRecordDecl. Called by Decl::Create.
|
||||
// FIXME: Implement this.
|
||||
static CXXRecordDecl* CreateImpl(Kind DK, llvm::Deserializer& D, ASTContext& C);
|
||||
|
||||
friend Decl* Decl::Create(llvm::Deserializer& D, ASTContext& C);
|
||||
};
|
||||
|
||||
/// CXXMethodDecl - Represents a static or instance method of a
|
||||
/// struct/union/class.
|
||||
class CXXMethodDecl : public FunctionDecl {
|
||||
protected:
|
||||
CXXMethodDecl(Kind DK, CXXRecordDecl *RD, SourceLocation L,
|
||||
DeclarationName N, QualType T,
|
||||
bool isStatic, bool isInline)
|
||||
: FunctionDecl(DK, RD, L, N, T, (isStatic ? Static : None),
|
||||
isInline) {}
|
||||
|
||||
public:
|
||||
static CXXMethodDecl *Create(ASTContext &C, CXXRecordDecl *RD,
|
||||
SourceLocation L, DeclarationName N,
|
||||
QualType T, bool isStatic = false,
|
||||
bool isInline = false);
|
||||
|
||||
bool isStatic() const { return getStorageClass() == Static; }
|
||||
bool isInstance() const { return !isStatic(); }
|
||||
|
||||
bool isOutOfLineDefinition() const {
|
||||
return getLexicalDeclContext() != getDeclContext();
|
||||
}
|
||||
|
||||
/// getParent - Returns the parent of this method declaration, which
|
||||
/// is the class in which this method is defined.
|
||||
const CXXRecordDecl *getParent() const {
|
||||
return cast<CXXRecordDecl>(FunctionDecl::getParent());
|
||||
}
|
||||
|
||||
/// getParent - Returns the parent of this method declaration, which
|
||||
/// is the class in which this method is defined.
|
||||
CXXRecordDecl *getParent() {
|
||||
return const_cast<CXXRecordDecl *>(
|
||||
cast<CXXRecordDecl>(FunctionDecl::getParent()));
|
||||
}
|
||||
|
||||
/// getThisType - Returns the type of 'this' pointer.
|
||||
/// Should only be called for instance methods.
|
||||
QualType getThisType(ASTContext &C) const;
|
||||
|
||||
unsigned getTypeQualifiers() const {
|
||||
return getType()->getAsFunctionTypeProto()->getTypeQuals();
|
||||
}
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) {
|
||||
return D->getKind() >= CXXMethod && D->getKind() <= CXXConversion;
|
||||
}
|
||||
static bool classof(const CXXMethodDecl *D) { return true; }
|
||||
static DeclContext *castToDeclContext(const CXXMethodDecl *D) {
|
||||
return static_cast<DeclContext *>(const_cast<CXXMethodDecl*>(D));
|
||||
}
|
||||
static CXXMethodDecl *castFromDeclContext(const DeclContext *DC) {
|
||||
return static_cast<CXXMethodDecl *>(const_cast<DeclContext*>(DC));
|
||||
}
|
||||
|
||||
protected:
|
||||
/// EmitImpl - Serialize this CXXMethodDecl. Called by Decl::Emit.
|
||||
// FIXME: Implement this.
|
||||
//virtual void EmitImpl(llvm::Serializer& S) const;
|
||||
|
||||
/// CreateImpl - Deserialize a CXXMethodDecl. Called by Decl::Create.
|
||||
// FIXME: Implement this.
|
||||
static CXXMethodDecl* CreateImpl(llvm::Deserializer& D, ASTContext& C);
|
||||
|
||||
friend Decl* Decl::Create(llvm::Deserializer& D, ASTContext& C);
|
||||
};
|
||||
|
||||
/// CXXBaseOrMemberInitializer - Represents a C++ base or member
|
||||
/// initializer, which is part of a constructor initializer that
|
||||
/// initializes one non-static member variable or one base class. For
|
||||
/// example, in the following, both 'A(a)' and 'f(3.14159)' are member
|
||||
/// initializers:
|
||||
///
|
||||
/// @code
|
||||
/// class A { };
|
||||
/// class B : public A {
|
||||
/// float f;
|
||||
/// public:
|
||||
/// B(A& a) : A(a), f(3.14159) { }
|
||||
/// };
|
||||
class CXXBaseOrMemberInitializer {
|
||||
/// BaseOrMember - This points to the entity being initialized,
|
||||
/// which is either a base class (a Type) or a non-static data
|
||||
/// member. When the low bit is 1, it's a base
|
||||
/// class; when the low bit is 0, it's a member.
|
||||
uintptr_t BaseOrMember;
|
||||
|
||||
/// Args - The arguments used to initialize the base or member.
|
||||
Expr **Args;
|
||||
unsigned NumArgs;
|
||||
|
||||
public:
|
||||
/// CXXBaseOrMemberInitializer - Creates a new base-class initializer.
|
||||
explicit
|
||||
CXXBaseOrMemberInitializer(QualType BaseType, Expr **Args, unsigned NumArgs);
|
||||
|
||||
/// CXXBaseOrMemberInitializer - Creates a new member initializer.
|
||||
explicit
|
||||
CXXBaseOrMemberInitializer(FieldDecl *Member, Expr **Args, unsigned NumArgs);
|
||||
|
||||
/// ~CXXBaseOrMemberInitializer - Destroy the base or member initializer.
|
||||
~CXXBaseOrMemberInitializer();
|
||||
|
||||
/// arg_iterator - Iterates through the member initialization
|
||||
/// arguments.
|
||||
typedef Expr **arg_iterator;
|
||||
|
||||
/// arg_const_iterator - Iterates through the member initialization
|
||||
/// arguments.
|
||||
typedef Expr * const * arg_const_iterator;
|
||||
|
||||
/// isBaseInitializer - Returns true when this initializer is
|
||||
/// initializing a base class.
|
||||
bool isBaseInitializer() const { return (BaseOrMember & 0x1) != 0; }
|
||||
|
||||
/// isMemberInitializer - Returns true when this initializer is
|
||||
/// initializing a non-static data member.
|
||||
bool isMemberInitializer() const { return (BaseOrMember & 0x1) == 0; }
|
||||
|
||||
/// getBaseClass - If this is a base class initializer, returns the
|
||||
/// type used to specify the initializer. The resulting type will be
|
||||
/// a class type or a typedef of a class type. If this is not a base
|
||||
/// class initializer, returns NULL.
|
||||
Type *getBaseClass() {
|
||||
if (isBaseInitializer())
|
||||
return reinterpret_cast<Type*>(BaseOrMember & ~0x01);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// getBaseClass - If this is a base class initializer, returns the
|
||||
/// type used to specify the initializer. The resulting type will be
|
||||
/// a class type or a typedef of a class type. If this is not a base
|
||||
/// class initializer, returns NULL.
|
||||
const Type *getBaseClass() const {
|
||||
if (isBaseInitializer())
|
||||
return reinterpret_cast<const Type*>(BaseOrMember & ~0x01);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// getMember - If this is a member initializer, returns the
|
||||
/// declaration of the non-static data member being
|
||||
/// initialized. Otherwise, returns NULL.
|
||||
FieldDecl *getMember() {
|
||||
if (isMemberInitializer())
|
||||
return reinterpret_cast<FieldDecl *>(BaseOrMember);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// begin() - Retrieve an iterator to the first initializer argument.
|
||||
arg_iterator begin() { return Args; }
|
||||
/// begin() - Retrieve an iterator to the first initializer argument.
|
||||
arg_const_iterator begin() const { return Args; }
|
||||
|
||||
/// end() - Retrieve an iterator past the last initializer argument.
|
||||
arg_iterator end() { return Args + NumArgs; }
|
||||
/// end() - Retrieve an iterator past the last initializer argument.
|
||||
arg_const_iterator end() const { return Args + NumArgs; }
|
||||
|
||||
/// getNumArgs - Determine the number of arguments used to
|
||||
/// initialize the member or base.
|
||||
unsigned getNumArgs() const { return NumArgs; }
|
||||
};
|
||||
|
||||
/// CXXConstructorDecl - Represents a C++ constructor within a
|
||||
/// class. For example:
|
||||
///
|
||||
/// @code
|
||||
/// class X {
|
||||
/// public:
|
||||
/// explicit X(int); // represented by a CXXConstructorDecl.
|
||||
/// };
|
||||
/// @endcode
|
||||
class CXXConstructorDecl : public CXXMethodDecl {
|
||||
/// Explicit - Whether this constructor is explicit.
|
||||
bool Explicit : 1;
|
||||
|
||||
/// ImplicitlyDefined - Whether this constructor was implicitly
|
||||
/// defined by the compiler. When false, the constructor was defined
|
||||
/// by the user. In C++03, this flag will have the same value as
|
||||
/// Implicit. In C++0x, however, a constructor that is
|
||||
/// explicitly defaulted (i.e., defined with " = default") will have
|
||||
/// @c !Implicit && ImplicitlyDefined.
|
||||
bool ImplicitlyDefined : 1;
|
||||
|
||||
/// FIXME: Add support for base and member initializers.
|
||||
|
||||
CXXConstructorDecl(CXXRecordDecl *RD, SourceLocation L,
|
||||
DeclarationName N, QualType T,
|
||||
bool isExplicit, bool isInline, bool isImplicitlyDeclared)
|
||||
: CXXMethodDecl(CXXConstructor, RD, L, N, T, false, isInline),
|
||||
Explicit(isExplicit), ImplicitlyDefined(false) {
|
||||
setImplicit(isImplicitlyDeclared);
|
||||
}
|
||||
|
||||
public:
|
||||
static CXXConstructorDecl *Create(ASTContext &C, CXXRecordDecl *RD,
|
||||
SourceLocation L, DeclarationName N,
|
||||
QualType T, bool isExplicit,
|
||||
bool isInline, bool isImplicitlyDeclared);
|
||||
|
||||
/// isExplicit - Whether this constructor was marked "explicit" or not.
|
||||
bool isExplicit() const { return Explicit; }
|
||||
|
||||
/// isImplicitlyDefined - Whether this constructor was implicitly
|
||||
/// defined. If false, then this constructor was defined by the
|
||||
/// user. This operation can only be invoked if the constructor has
|
||||
/// already been defined.
|
||||
bool isImplicitlyDefined() const {
|
||||
assert(getBody() != 0 &&
|
||||
"Can only get the implicit-definition flag once the constructor has been defined");
|
||||
return ImplicitlyDefined;
|
||||
}
|
||||
|
||||
/// setImplicitlyDefined - Set whether this constructor was
|
||||
/// implicitly defined or not.
|
||||
void setImplicitlyDefined(bool ID) {
|
||||
assert(getBody() != 0 &&
|
||||
"Can only set the implicit-definition flag once the constructor has been defined");
|
||||
ImplicitlyDefined = ID;
|
||||
}
|
||||
|
||||
/// isDefaultConstructor - Whether this constructor is a default
|
||||
/// constructor (C++ [class.ctor]p5), which can be used to
|
||||
/// default-initialize a class of this type.
|
||||
bool isDefaultConstructor() const;
|
||||
|
||||
/// isCopyConstructor - Whether this constructor is a copy
|
||||
/// constructor (C++ [class.copy]p2, which can be used to copy the
|
||||
/// class. @p TypeQuals will be set to the qualifiers on the
|
||||
/// argument type. For example, @p TypeQuals would be set to @c
|
||||
/// QualType::Const for the following copy constructor:
|
||||
///
|
||||
/// @code
|
||||
/// class X {
|
||||
/// public:
|
||||
/// X(const X&);
|
||||
/// };
|
||||
/// @endcode
|
||||
bool isCopyConstructor(ASTContext &Context, unsigned &TypeQuals) const;
|
||||
|
||||
/// isCopyConstructor - Whether this constructor is a copy
|
||||
/// constructor (C++ [class.copy]p2, which can be used to copy the
|
||||
/// class.
|
||||
bool isCopyConstructor(ASTContext &Context) const {
|
||||
unsigned TypeQuals = 0;
|
||||
return isCopyConstructor(Context, TypeQuals);
|
||||
}
|
||||
|
||||
/// isConvertingConstructor - Whether this constructor is a
|
||||
/// converting constructor (C++ [class.conv.ctor]), which can be
|
||||
/// used for user-defined conversions.
|
||||
bool isConvertingConstructor() const;
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) {
|
||||
return D->getKind() == CXXConstructor;
|
||||
}
|
||||
static bool classof(const CXXConstructorDecl *D) { return true; }
|
||||
static DeclContext *castToDeclContext(const CXXConstructorDecl *D) {
|
||||
return static_cast<DeclContext *>(const_cast<CXXConstructorDecl*>(D));
|
||||
}
|
||||
static CXXConstructorDecl *castFromDeclContext(const DeclContext *DC) {
|
||||
return static_cast<CXXConstructorDecl *>(const_cast<DeclContext*>(DC));
|
||||
}
|
||||
/// EmitImpl - Serialize this CXXConstructorDecl. Called by Decl::Emit.
|
||||
// FIXME: Implement this.
|
||||
//virtual void EmitImpl(llvm::Serializer& S) const;
|
||||
|
||||
/// CreateImpl - Deserialize a CXXConstructorDecl. Called by Decl::Create.
|
||||
// FIXME: Implement this.
|
||||
static CXXConstructorDecl* CreateImpl(llvm::Deserializer& D, ASTContext& C);
|
||||
};
|
||||
|
||||
/// CXXDestructorDecl - Represents a C++ destructor within a
|
||||
/// class. For example:
|
||||
///
|
||||
/// @code
|
||||
/// class X {
|
||||
/// public:
|
||||
/// ~X(); // represented by a CXXDestructorDecl.
|
||||
/// };
|
||||
/// @endcode
|
||||
class CXXDestructorDecl : public CXXMethodDecl {
|
||||
/// ImplicitlyDefined - Whether this destructor was implicitly
|
||||
/// defined by the compiler. When false, the destructor was defined
|
||||
/// by the user. In C++03, this flag will have the same value as
|
||||
/// Implicit. In C++0x, however, a destructor that is
|
||||
/// explicitly defaulted (i.e., defined with " = default") will have
|
||||
/// @c !Implicit && ImplicitlyDefined.
|
||||
bool ImplicitlyDefined : 1;
|
||||
|
||||
CXXDestructorDecl(CXXRecordDecl *RD, SourceLocation L,
|
||||
DeclarationName N, QualType T,
|
||||
bool isInline, bool isImplicitlyDeclared)
|
||||
: CXXMethodDecl(CXXDestructor, RD, L, N, T, false, isInline),
|
||||
ImplicitlyDefined(false) {
|
||||
setImplicit(isImplicitlyDeclared);
|
||||
}
|
||||
|
||||
public:
|
||||
static CXXDestructorDecl *Create(ASTContext &C, CXXRecordDecl *RD,
|
||||
SourceLocation L, DeclarationName N,
|
||||
QualType T, bool isInline,
|
||||
bool isImplicitlyDeclared);
|
||||
|
||||
/// isImplicitlyDefined - Whether this destructor was implicitly
|
||||
/// defined. If false, then this destructor was defined by the
|
||||
/// user. This operation can only be invoked if the destructor has
|
||||
/// already been defined.
|
||||
bool isImplicitlyDefined() const {
|
||||
assert(getBody() != 0 &&
|
||||
"Can only get the implicit-definition flag once the destructor has been defined");
|
||||
return ImplicitlyDefined;
|
||||
}
|
||||
|
||||
/// setImplicitlyDefined - Set whether this destructor was
|
||||
/// implicitly defined or not.
|
||||
void setImplicitlyDefined(bool ID) {
|
||||
assert(getBody() != 0 &&
|
||||
"Can only set the implicit-definition flag once the destructor has been defined");
|
||||
ImplicitlyDefined = ID;
|
||||
}
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) {
|
||||
return D->getKind() == CXXDestructor;
|
||||
}
|
||||
static bool classof(const CXXDestructorDecl *D) { return true; }
|
||||
static DeclContext *castToDeclContext(const CXXDestructorDecl *D) {
|
||||
return static_cast<DeclContext *>(const_cast<CXXDestructorDecl*>(D));
|
||||
}
|
||||
static CXXDestructorDecl *castFromDeclContext(const DeclContext *DC) {
|
||||
return static_cast<CXXDestructorDecl *>(const_cast<DeclContext*>(DC));
|
||||
}
|
||||
/// EmitImpl - Serialize this CXXDestructorDecl. Called by Decl::Emit.
|
||||
// FIXME: Implement this.
|
||||
//virtual void EmitImpl(llvm::Serializer& S) const;
|
||||
|
||||
/// CreateImpl - Deserialize a CXXDestructorDecl. Called by Decl::Create.
|
||||
// FIXME: Implement this.
|
||||
static CXXDestructorDecl* CreateImpl(llvm::Deserializer& D, ASTContext& C);
|
||||
};
|
||||
|
||||
/// CXXConversionDecl - Represents a C++ conversion function within a
|
||||
/// class. For example:
|
||||
///
|
||||
/// @code
|
||||
/// class X {
|
||||
/// public:
|
||||
/// operator bool();
|
||||
/// };
|
||||
/// @endcode
|
||||
class CXXConversionDecl : public CXXMethodDecl {
|
||||
/// Explicit - Whether this conversion function is marked
|
||||
/// "explicit", meaning that it can only be applied when the user
|
||||
/// explicitly wrote a cast. This is a C++0x feature.
|
||||
bool Explicit : 1;
|
||||
|
||||
CXXConversionDecl(CXXRecordDecl *RD, SourceLocation L,
|
||||
DeclarationName N, QualType T,
|
||||
bool isInline, bool isExplicit)
|
||||
: CXXMethodDecl(CXXConversion, RD, L, N, T, false, isInline),
|
||||
Explicit(isExplicit) { }
|
||||
|
||||
public:
|
||||
static CXXConversionDecl *Create(ASTContext &C, CXXRecordDecl *RD,
|
||||
SourceLocation L, DeclarationName N,
|
||||
QualType T, bool isInline,
|
||||
bool isExplicit);
|
||||
|
||||
/// isExplicit - Whether this is an explicit conversion operator
|
||||
/// (C++0x only). Explicit conversion operators are only considered
|
||||
/// when the user has explicitly written a cast.
|
||||
bool isExplicit() const { return Explicit; }
|
||||
|
||||
/// getConversionType - Returns the type that this conversion
|
||||
/// function is converting to.
|
||||
QualType getConversionType() const {
|
||||
return getType()->getAsFunctionType()->getResultType();
|
||||
}
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) {
|
||||
return D->getKind() == CXXConversion;
|
||||
}
|
||||
static bool classof(const CXXConversionDecl *D) { return true; }
|
||||
static DeclContext *castToDeclContext(const CXXConversionDecl *D) {
|
||||
return static_cast<DeclContext *>(const_cast<CXXConversionDecl*>(D));
|
||||
}
|
||||
static CXXConversionDecl *castFromDeclContext(const DeclContext *DC) {
|
||||
return static_cast<CXXConversionDecl *>(const_cast<DeclContext*>(DC));
|
||||
}
|
||||
/// EmitImpl - Serialize this CXXConversionDecl. Called by Decl::Emit.
|
||||
// FIXME: Implement this.
|
||||
//virtual void EmitImpl(llvm::Serializer& S) const;
|
||||
|
||||
/// CreateImpl - Deserialize a CXXConversionDecl. Called by Decl::Create.
|
||||
// FIXME: Implement this.
|
||||
static CXXConversionDecl* CreateImpl(llvm::Deserializer& D, ASTContext& C);
|
||||
};
|
||||
|
||||
/// CXXClassVarDecl - Represents a static data member of a struct/union/class.
|
||||
class CXXClassVarDecl : public VarDecl {
|
||||
|
||||
CXXClassVarDecl(CXXRecordDecl *RD, SourceLocation L,
|
||||
IdentifierInfo *Id, QualType T)
|
||||
: VarDecl(CXXClassVar, RD, L, Id, T, None) {}
|
||||
public:
|
||||
static CXXClassVarDecl *Create(ASTContext &C, CXXRecordDecl *RD,
|
||||
SourceLocation L,IdentifierInfo *Id,
|
||||
QualType T);
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return D->getKind() == CXXClassVar; }
|
||||
static bool classof(const CXXClassVarDecl *D) { return true; }
|
||||
|
||||
protected:
|
||||
/// EmitImpl - Serialize this CXXClassVarDecl. Called by Decl::Emit.
|
||||
// FIXME: Implement this.
|
||||
//virtual void EmitImpl(llvm::Serializer& S) const;
|
||||
|
||||
/// CreateImpl - Deserialize a CXXClassVarDecl. Called by Decl::Create.
|
||||
// FIXME: Implement this.
|
||||
static CXXClassVarDecl* CreateImpl(llvm::Deserializer& D, ASTContext& C);
|
||||
|
||||
friend Decl* Decl::Create(llvm::Deserializer& D, ASTContext& C);
|
||||
};
|
||||
|
||||
|
||||
/// CXXClassMemberWrapper - A wrapper class for C++ class member decls.
|
||||
/// Common functions like set/getAccess are included here to avoid bloating
|
||||
/// the interface of non-C++ specific decl classes, like NamedDecl.
|
||||
/// FIXME: Doug would like to remove this class.
|
||||
class CXXClassMemberWrapper {
|
||||
Decl *MD;
|
||||
|
||||
public:
|
||||
CXXClassMemberWrapper(Decl *D) : MD(D) {
|
||||
assert(isMember(D) && "Not a C++ class member!");
|
||||
}
|
||||
|
||||
AccessSpecifier getAccess() const {
|
||||
return AccessSpecifier(MD->Access);
|
||||
}
|
||||
|
||||
void setAccess(AccessSpecifier AS) {
|
||||
assert(AS != AS_none && "Access must be specified.");
|
||||
MD->Access = AS;
|
||||
}
|
||||
|
||||
CXXRecordDecl *getParent() const {
|
||||
return dyn_cast<CXXRecordDecl>(MD->getDeclContext());
|
||||
}
|
||||
|
||||
static bool isMember(Decl *D) {
|
||||
return isa<CXXRecordDecl>(D->getDeclContext());
|
||||
}
|
||||
};
|
||||
|
||||
/// LinkageSpecDecl - This represents a linkage specification. For example:
|
||||
/// extern "C" void foo();
|
||||
///
|
||||
class LinkageSpecDecl : public Decl, public DeclContext {
|
||||
public:
|
||||
/// LanguageIDs - Used to represent the language in a linkage
|
||||
/// specification. The values are part of the serialization abi for
|
||||
/// ASTs and cannot be changed without altering that abi. To help
|
||||
/// ensure a stable abi for this, we choose the DW_LANG_ encodings
|
||||
/// from the dwarf standard.
|
||||
enum LanguageIDs { lang_c = /* DW_LANG_C */ 0x0002,
|
||||
lang_cxx = /* DW_LANG_C_plus_plus */ 0x0004 };
|
||||
private:
|
||||
/// Language - The language for this linkage specification.
|
||||
LanguageIDs Language;
|
||||
|
||||
/// HadBraces - Whether this linkage specification had curly braces or not.
|
||||
bool HadBraces : 1;
|
||||
|
||||
LinkageSpecDecl(DeclContext *DC, SourceLocation L, LanguageIDs lang,
|
||||
bool Braces)
|
||||
: Decl(LinkageSpec, DC, L),
|
||||
DeclContext(LinkageSpec), Language(lang), HadBraces(Braces) { }
|
||||
|
||||
public:
|
||||
static LinkageSpecDecl *Create(ASTContext &C, DeclContext *DC,
|
||||
SourceLocation L, LanguageIDs Lang,
|
||||
bool Braces);
|
||||
|
||||
LanguageIDs getLanguage() const { return Language; }
|
||||
|
||||
/// hasBraces - Determines whether this linkage specification had
|
||||
/// braces in its syntactic form.
|
||||
bool hasBraces() const { return HadBraces; }
|
||||
|
||||
static bool classof(const Decl *D) {
|
||||
return D->getKind() == LinkageSpec;
|
||||
}
|
||||
static bool classof(const LinkageSpecDecl *D) { return true; }
|
||||
|
||||
protected:
|
||||
void EmitInRec(llvm::Serializer& S) const;
|
||||
void ReadInRec(llvm::Deserializer& D, ASTContext& C);
|
||||
};
|
||||
|
||||
/// TemplateParameterList - Stores a list of template parameters.
|
||||
class TemplateParameterList {
|
||||
/// NumParams - The number of template parameters in this template
|
||||
/// parameter list.
|
||||
unsigned NumParams;
|
||||
|
||||
TemplateParameterList(Decl **Params, unsigned NumParams);
|
||||
|
||||
public:
|
||||
static TemplateParameterList *Create(ASTContext &C, Decl **Params,
|
||||
unsigned NumParams);
|
||||
|
||||
/// iterator - Iterates through the template parameters in this list.
|
||||
typedef Decl** iterator;
|
||||
|
||||
/// const_iterator - Iterates through the template parameters in this list.
|
||||
typedef Decl* const* const_iterator;
|
||||
|
||||
iterator begin() { return reinterpret_cast<Decl **>(this + 1); }
|
||||
const_iterator begin() const {
|
||||
return reinterpret_cast<Decl * const *>(this + 1);
|
||||
}
|
||||
iterator end() { return begin() + NumParams; }
|
||||
const_iterator end() const { return begin() + NumParams; }
|
||||
|
||||
unsigned size() const { return NumParams; }
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
@@ -1,139 +0,0 @@
|
||||
//===--- DeclGroup.h - Classes for representing groups of Decls -*- 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 DeclGroup, DeclGroupRef, and OwningDeclGroup classes.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_DECLGROUP_H
|
||||
#define LLVM_CLANG_AST_DECLGROUP_H
|
||||
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include "llvm/Bitcode/SerializationFwd.h"
|
||||
#include <cassert>
|
||||
|
||||
namespace clang {
|
||||
|
||||
class ASTContext;
|
||||
class Decl;
|
||||
class DeclGroup;
|
||||
class DeclGroupIterator;
|
||||
|
||||
class DeclGroup {
|
||||
// FIXME: Include a TypeSpecifier object.
|
||||
unsigned NumDecls;
|
||||
|
||||
private:
|
||||
DeclGroup() : NumDecls(0) {}
|
||||
DeclGroup(unsigned numdecls, Decl** decls);
|
||||
|
||||
public:
|
||||
static DeclGroup* Create(ASTContext& C, unsigned numdecls, Decl** decls);
|
||||
void Destroy(ASTContext& C);
|
||||
|
||||
unsigned size() const { return NumDecls; }
|
||||
|
||||
Decl*& operator[](unsigned i) {
|
||||
assert (i < NumDecls && "Out-of-bounds access.");
|
||||
return *((Decl**) (this+1));
|
||||
}
|
||||
|
||||
Decl* const& operator[](unsigned i) const {
|
||||
assert (i < NumDecls && "Out-of-bounds access.");
|
||||
return *((Decl* const*) (this+1));
|
||||
}
|
||||
|
||||
/// Emit - Serialize a DeclGroup to Bitcode.
|
||||
void Emit(llvm::Serializer& S) const;
|
||||
|
||||
/// Read - Deserialize a DeclGroup from Bitcode.
|
||||
static DeclGroup* Create(llvm::Deserializer& D, ASTContext& C);
|
||||
};
|
||||
|
||||
class DeclGroupRef {
|
||||
protected:
|
||||
enum Kind { DeclKind=0x0, DeclGroupKind=0x1, Mask=0x1 };
|
||||
Decl* D;
|
||||
|
||||
Kind getKind() const {
|
||||
return (Kind) (reinterpret_cast<uintptr_t>(D) & Mask);
|
||||
}
|
||||
|
||||
public:
|
||||
DeclGroupRef() : D(0) {}
|
||||
|
||||
explicit DeclGroupRef(Decl* d) : D(d) {}
|
||||
explicit DeclGroupRef(DeclGroup* dg)
|
||||
: D((Decl*) (reinterpret_cast<uintptr_t>(dg) | DeclGroupKind)) {}
|
||||
|
||||
typedef Decl** iterator;
|
||||
typedef Decl* const * const_iterator;
|
||||
|
||||
bool hasSolitaryDecl() const {
|
||||
return getKind() == DeclKind;
|
||||
}
|
||||
|
||||
iterator begin() {
|
||||
if (getKind() == DeclKind) return D ? &D : 0;
|
||||
DeclGroup& G = *((DeclGroup*) (reinterpret_cast<uintptr_t>(D) & ~Mask));
|
||||
return &G[0];
|
||||
}
|
||||
|
||||
iterator end() {
|
||||
if (getKind() == DeclKind) return D ? &D + 1 : 0;
|
||||
DeclGroup& G = *((DeclGroup*) (reinterpret_cast<uintptr_t>(D) & ~Mask));
|
||||
return &G[0] + G.size();
|
||||
}
|
||||
|
||||
const_iterator begin() const {
|
||||
if (getKind() == DeclKind) return D ? &D : 0;
|
||||
DeclGroup& G = *((DeclGroup*) (reinterpret_cast<uintptr_t>(D) & ~Mask));
|
||||
return &G[0];
|
||||
}
|
||||
|
||||
const_iterator end() const {
|
||||
if (getKind() == DeclKind) return D ? &D + 1 : 0;
|
||||
DeclGroup& G = *((DeclGroup*) (reinterpret_cast<uintptr_t>(D) & ~Mask));
|
||||
return &G[0] + G.size();
|
||||
}
|
||||
|
||||
/// Emit - Serialize a DeclGroupRef to Bitcode.
|
||||
void Emit(llvm::Serializer& S) const;
|
||||
|
||||
/// Read - Deserialize a DeclGroupRef from Bitcode.
|
||||
static DeclGroupRef ReadVal(llvm::Deserializer& D);
|
||||
};
|
||||
|
||||
class DeclGroupOwningRef : public DeclGroupRef {
|
||||
public:
|
||||
explicit DeclGroupOwningRef() : DeclGroupRef((Decl*)0) {}
|
||||
explicit DeclGroupOwningRef(Decl* d) : DeclGroupRef(d) {}
|
||||
explicit DeclGroupOwningRef(DeclGroup* dg) : DeclGroupRef(dg) {}
|
||||
|
||||
~DeclGroupOwningRef();
|
||||
void Destroy(ASTContext& C);
|
||||
|
||||
DeclGroupOwningRef(DeclGroupOwningRef& R)
|
||||
: DeclGroupRef(R) { R.D = 0; }
|
||||
|
||||
DeclGroupOwningRef& operator=(DeclGroupOwningRef& R) {
|
||||
D = R.D;
|
||||
R.D = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Emit - Serialize a DeclGroupOwningRef to Bitcode.
|
||||
void Emit(llvm::Serializer& S) const;
|
||||
|
||||
/// Read - Deserialize a DeclGroupOwningRef from Bitcode.
|
||||
DeclGroupOwningRef& Read(llvm::Deserializer& D, ASTContext& C);
|
||||
};
|
||||
|
||||
} // end clang namespace
|
||||
#endif
|
||||
@@ -1,149 +0,0 @@
|
||||
//===-- DeclNodes.def - Metadata about Decl AST nodes -----------*- 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 declaration nodes within the AST. The
|
||||
// description of the declaration nodes uses six macros:
|
||||
//
|
||||
// DECL(Derived, Base) describes a normal declaration type Derived
|
||||
// and specifies its base class. Note that Derived should not have
|
||||
// the Decl suffix on it, while Base should.
|
||||
//
|
||||
// LAST_DECL(Derived, Base) is like DECL, but is used for the last
|
||||
// declaration in the list.
|
||||
//
|
||||
// ABSTRACT_DECL(Derived, Base) describes an abstract class that is
|
||||
// used to specify a classification of declarations. For example,
|
||||
// TagDecl is an abstract class used to describe the various kinds of
|
||||
// "tag" declarations (unions, structs, classes, enums).
|
||||
//
|
||||
// DECL_CONTEXT(Decl) specifies that Decl is a kind of declaration
|
||||
// that is also a DeclContext.
|
||||
//
|
||||
// LAST_DECL_CONTEXT(Decl) is like DECL_CONTEXT, but is used for the
|
||||
// last declaration context.
|
||||
//
|
||||
// DECL_RANGE(CommonBase, Start, End) specifies a range of
|
||||
// declaration values that have a common (potentially indirect) base
|
||||
// class.
|
||||
//
|
||||
// LAST_DECL_RANGE(CommonBase, Start, End) is like DECL_RANGE, but is
|
||||
// used for the last declaration range.
|
||||
//
|
||||
// Note that, due to the use of ranges, the order of the these
|
||||
// declarations is significant. A declaration should be listed under
|
||||
// its base class.
|
||||
// ===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef DECL
|
||||
# define DECL(Derived, Base)
|
||||
#endif
|
||||
|
||||
#ifndef LAST_DECL
|
||||
# define LAST_DECL(Derived, Base) DECL(Derived, Base)
|
||||
#endif
|
||||
|
||||
#ifndef ABSTRACT_DECL
|
||||
# define ABSTRACT_DECL(Derived, Base)
|
||||
#endif
|
||||
|
||||
#ifndef DECL_CONTEXT
|
||||
# define DECL_CONTEXT(Decl)
|
||||
#endif
|
||||
|
||||
#ifndef LAST_DECL_CONTEXT
|
||||
# define LAST_DECL_CONTEXT(Decl) DECL_CONTEXT(Decl)
|
||||
#endif
|
||||
|
||||
#ifndef DECL_RANGE
|
||||
# define DECL_RANGE(CommonBase, Start, End)
|
||||
#endif
|
||||
|
||||
#ifndef LAST_DECL_RANGE
|
||||
# define LAST_DECL_RANGE(CommonBase, Start, End) \
|
||||
DECL_RANGE(CommonBase, Start, End)
|
||||
#endif
|
||||
|
||||
DECL(TranslationUnit, Decl)
|
||||
ABSTRACT_DECL(Named, Decl)
|
||||
DECL(OverloadedFunction, NamedDecl)
|
||||
DECL(Field, NameDecl)
|
||||
DECL(ObjCIvar, FieldDecl)
|
||||
DECL(ObjCAtDefsField, FieldDecl)
|
||||
DECL(Namespace, NamedDecl)
|
||||
ABSTRACT_DECL(Type, NamedDecl)
|
||||
DECL(Typedef, TypeDecl)
|
||||
ABSTRACT_DECL(Tag, TypeDecl)
|
||||
DECL(Enum, TagDecl)
|
||||
DECL(Record, TagDecl)
|
||||
DECL(CXXRecord, RecordDecl)
|
||||
DECL(TemplateTypeParm, TypeDecl)
|
||||
ABSTRACT_DECL(Value, NamedDecl)
|
||||
DECL(EnumConstant, ValueDecl)
|
||||
DECL(Function, ValueDecl)
|
||||
DECL(CXXMethod, FunctionDecl)
|
||||
DECL(CXXConstructor, CXXMethodDecl)
|
||||
DECL(CXXDestructor, CXXMethodDecl)
|
||||
DECL(CXXConversion, CXXMethodDecl)
|
||||
DECL(Var, ValueDecl)
|
||||
DECL(ImplicitParam, VarDecl)
|
||||
DECL(CXXClassVar, VarDecl)
|
||||
DECL(ParmVar, VarDecl)
|
||||
DECL(OriginalParmVar, ParmVarDecl)
|
||||
DECL(NonTypeTemplateParm, VarDecl)
|
||||
DECL(ObjCMethod, NamedDecl)
|
||||
DECL(ObjCContainer, NamedDecl)
|
||||
DECL(ObjCCategory, ObjCContainerDecl)
|
||||
DECL(ObjCProtocol, ObjCContainerDecl)
|
||||
DECL(ObjCInterface, ObjCContainerDecl)
|
||||
DECL(ObjCCategoryImpl, NamedDecl)
|
||||
DECL(ObjCProperty, NamedDecl)
|
||||
DECL(ObjCCompatibleAlias, NamedDecl)
|
||||
DECL(LinkageSpec, Decl)
|
||||
DECL(ObjCPropertyImpl, Decl)
|
||||
DECL(ObjCImplementation, Decl)
|
||||
DECL(ObjCForwardProtocol, Decl)
|
||||
DECL(ObjCClass, Decl)
|
||||
DECL(FileScopeAsm, Decl)
|
||||
LAST_DECL(Block, Decl)
|
||||
|
||||
// Declaration contexts
|
||||
DECL_CONTEXT(TranslationUnit)
|
||||
DECL_CONTEXT(Namespace)
|
||||
DECL_CONTEXT(Enum)
|
||||
DECL_CONTEXT(Record)
|
||||
DECL_CONTEXT(CXXRecord)
|
||||
DECL_CONTEXT(Function)
|
||||
DECL_CONTEXT(ObjCMethod)
|
||||
DECL_CONTEXT(ObjCContainer)
|
||||
DECL_CONTEXT(ObjCInterface)
|
||||
DECL_CONTEXT(ObjCProtocol)
|
||||
DECL_CONTEXT(ObjCCategory)
|
||||
DECL_CONTEXT(ObjCCategoryImpl)
|
||||
DECL_CONTEXT(LinkageSpec)
|
||||
DECL_CONTEXT(ObjCImplementation)
|
||||
LAST_DECL_CONTEXT(Block)
|
||||
|
||||
// Declaration ranges
|
||||
DECL_RANGE(Named, OverloadedFunction, ObjCCompatibleAlias)
|
||||
DECL_RANGE(ObjCContainer, ObjCContainer, ObjCInterface)
|
||||
DECL_RANGE(Field, Field, ObjCAtDefsField)
|
||||
DECL_RANGE(Type, Typedef, TemplateTypeParm)
|
||||
DECL_RANGE(Tag, Enum, CXXRecord)
|
||||
DECL_RANGE(Record, Record, CXXRecord)
|
||||
DECL_RANGE(Value, EnumConstant, NonTypeTemplateParm)
|
||||
DECL_RANGE(Function, Function, CXXConversion)
|
||||
LAST_DECL_RANGE(Var, Var, NonTypeTemplateParm)
|
||||
|
||||
#undef LAST_DECL_RANGE
|
||||
#undef DECL_RANGE
|
||||
#undef LAST_DECL_CONTEXT
|
||||
#undef DECL_CONTEXT
|
||||
#undef ABSTRACT_DECL
|
||||
#undef LAST_DECL
|
||||
#undef DECL
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,364 +0,0 @@
|
||||
//===-- DeclarationName.h - Representation of declaration names -*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file declares the DeclarationName and DeclarationNameTable classes.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef LLVM_CLANG_AST_DECLARATIONNAME_H
|
||||
#define LLVM_CLANG_AST_DECLARATIONNAME_H
|
||||
|
||||
#include "clang/Basic/IdentifierTable.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "llvm/Bitcode/SerializationFwd.h"
|
||||
|
||||
namespace llvm {
|
||||
template <typename T> struct DenseMapInfo;
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
class CXXSpecialName;
|
||||
class CXXOperatorIdName;
|
||||
class DeclarationNameExtra;
|
||||
class IdentifierInfo;
|
||||
class MultiKeywordSelector;
|
||||
|
||||
/// DeclarationName - The name of a declaration. In the common case,
|
||||
/// this just stores an IdentifierInfo pointer to a normal
|
||||
/// name. However, it also provides encodings for Objective-C
|
||||
/// selectors (optimizing zero- and one-argument selectors, which make
|
||||
/// up 78% percent of all selectors in Cocoa.h) and special C++ names
|
||||
/// for constructors, destructors, and conversion functions.
|
||||
class DeclarationName {
|
||||
public:
|
||||
/// NameKind - The kind of name this object contains.
|
||||
enum NameKind {
|
||||
Identifier,
|
||||
ObjCZeroArgSelector,
|
||||
ObjCOneArgSelector,
|
||||
ObjCMultiArgSelector,
|
||||
CXXConstructorName,
|
||||
CXXDestructorName,
|
||||
CXXConversionFunctionName,
|
||||
CXXOperatorName
|
||||
};
|
||||
|
||||
private:
|
||||
/// StoredNameKind - The kind of name that is actually stored in the
|
||||
/// upper bits of the Ptr field. This is only used internally.
|
||||
enum StoredNameKind {
|
||||
StoredIdentifier = 0,
|
||||
StoredObjCZeroArgSelector,
|
||||
StoredObjCOneArgSelector,
|
||||
StoredDeclarationNameExtra,
|
||||
PtrMask = 0x03
|
||||
};
|
||||
|
||||
/// Ptr - The lowest two bits are used to express what kind of name
|
||||
/// we're actually storing, using the values of NameKind. Depending
|
||||
/// on the kind of name this is, the upper bits of Ptr may have one
|
||||
/// of several different meanings:
|
||||
///
|
||||
/// StoredIdentifier - The name is a normal identifier, and Ptr is
|
||||
/// a normal IdentifierInfo pointer.
|
||||
///
|
||||
/// StoredObjCZeroArgSelector - The name is an Objective-C
|
||||
/// selector with zero arguments, and Ptr is an IdentifierInfo
|
||||
/// pointer pointing to the selector name.
|
||||
///
|
||||
/// StoredObjCOneArgSelector - The name is an Objective-C selector
|
||||
/// with one argument, and Ptr is an IdentifierInfo pointer
|
||||
/// pointing to the selector name.
|
||||
///
|
||||
/// StoredDeclarationNameExtra - Ptr is actually a pointer to a
|
||||
/// 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;
|
||||
|
||||
/// getStoredNameKind - Return the kind of object that is stored in
|
||||
/// Ptr.
|
||||
StoredNameKind getStoredNameKind() const {
|
||||
return static_cast<StoredNameKind>(Ptr & PtrMask);
|
||||
}
|
||||
|
||||
/// getExtra - Get the "extra" information associated with this
|
||||
/// multi-argument selector or C++ special name.
|
||||
DeclarationNameExtra *getExtra() const {
|
||||
assert(getStoredNameKind() == StoredDeclarationNameExtra &&
|
||||
"Declaration name does not store an Extra structure");
|
||||
return reinterpret_cast<DeclarationNameExtra *>(Ptr & ~PtrMask);
|
||||
}
|
||||
|
||||
/// getAsCXXSpecialName - If the stored pointer is actually a
|
||||
/// CXXSpecialName, returns a pointer to it. Otherwise, returns
|
||||
/// a NULL pointer.
|
||||
CXXSpecialName *getAsCXXSpecialName() const {
|
||||
if (getNameKind() >= CXXConstructorName &&
|
||||
getNameKind() <= CXXConversionFunctionName)
|
||||
return reinterpret_cast<CXXSpecialName *>(Ptr & ~PtrMask);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// getAsCXXOperatorIdName
|
||||
CXXOperatorIdName *getAsCXXOperatorIdName() const {
|
||||
if (getNameKind() == CXXOperatorName)
|
||||
return reinterpret_cast<CXXOperatorIdName *>(Ptr & ~PtrMask);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Construct a declaration name from the name of a C++ constructor,
|
||||
// destructor, or conversion function.
|
||||
DeclarationName(CXXSpecialName *Name)
|
||||
: Ptr(reinterpret_cast<uintptr_t>(Name)) {
|
||||
assert((Ptr & PtrMask) == 0 && "Improperly aligned CXXSpecialName");
|
||||
Ptr |= StoredDeclarationNameExtra;
|
||||
}
|
||||
|
||||
// Construct a declaration name from the name of a C++ overloaded
|
||||
// operator.
|
||||
DeclarationName(CXXOperatorIdName *Name)
|
||||
: Ptr(reinterpret_cast<uintptr_t>(Name)) {
|
||||
assert((Ptr & PtrMask) == 0 && "Improperly aligned CXXOperatorId");
|
||||
Ptr |= StoredDeclarationNameExtra;
|
||||
}
|
||||
|
||||
// Construct a declaration name from a zero- or one-argument
|
||||
// Objective-C selector.
|
||||
DeclarationName(IdentifierInfo *II, unsigned numArgs)
|
||||
: Ptr(reinterpret_cast<uintptr_t>(II)) {
|
||||
assert((Ptr & PtrMask) == 0 && "Improperly aligned IdentifierInfo");
|
||||
assert(numArgs < 2 && "Use MultiKeywordSelector for >= 2 arguments");
|
||||
if (numArgs == 0)
|
||||
Ptr |= StoredObjCZeroArgSelector;
|
||||
else
|
||||
Ptr |= StoredObjCOneArgSelector;
|
||||
}
|
||||
|
||||
// Construct a declaration name from an Objective-C multiple-keyword
|
||||
// selector.
|
||||
DeclarationName(MultiKeywordSelector *SI)
|
||||
: Ptr(reinterpret_cast<uintptr_t>(SI)) {
|
||||
assert((Ptr & PtrMask) == 0 && "Improperly aligned MultiKeywordSelector");
|
||||
Ptr |= StoredDeclarationNameExtra;
|
||||
}
|
||||
|
||||
/// Construct a declaration name from a raw pointer.
|
||||
DeclarationName(uintptr_t Ptr) : Ptr(Ptr) { }
|
||||
|
||||
friend class DeclarationNameTable;
|
||||
|
||||
/// getFETokenInfoAsVoid - Retrieves the front end-specified pointer
|
||||
/// for this name as a void pointer.
|
||||
void *getFETokenInfoAsVoid() const;
|
||||
|
||||
public:
|
||||
/// DeclarationName - Used to create an empty selector.
|
||||
DeclarationName() : Ptr(0) { }
|
||||
|
||||
// Construct a declaration name from an IdentifierInfo *.
|
||||
DeclarationName(IdentifierInfo *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);
|
||||
|
||||
// operator bool() - Evaluates true when this declaration name is
|
||||
// non-empty.
|
||||
operator bool() const {
|
||||
return ((Ptr & PtrMask) != 0) ||
|
||||
(reinterpret_cast<IdentifierInfo *>(Ptr & ~PtrMask));
|
||||
}
|
||||
|
||||
/// getNameKind - Determine what kind of name this is.
|
||||
NameKind getNameKind() const;
|
||||
|
||||
/// getName - Retrieve the human-readable string for this name.
|
||||
std::string getAsString() const;
|
||||
|
||||
/// getAsIdentifierInfo - Retrieve the IdentifierInfo * stored in
|
||||
/// this declaration name, or NULL if this declaration name isn't a
|
||||
/// simple identifier.
|
||||
IdentifierInfo *getAsIdentifierInfo() const {
|
||||
if (getNameKind() == Identifier)
|
||||
return reinterpret_cast<IdentifierInfo *>(Ptr);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// getAsOpaqueInteger - Get the representation of this declaration
|
||||
/// name as an opaque integer.
|
||||
uintptr_t getAsOpaqueInteger() const { return Ptr; }
|
||||
|
||||
/// getAsOpaquePtr - Get the representation of this declaration name as
|
||||
/// an opaque pointer.
|
||||
void *getAsOpaquePtr() const { return reinterpret_cast<void*>(Ptr); }
|
||||
|
||||
static DeclarationName getFromOpaqueInteger(uintptr_t P) {
|
||||
DeclarationName N;
|
||||
N.Ptr = P;
|
||||
return N;
|
||||
}
|
||||
|
||||
/// getCXXNameType - If this name is one of the C++ names (of a
|
||||
/// constructor, destructor, or conversion function), return the
|
||||
/// type associated with that name.
|
||||
QualType getCXXNameType() const;
|
||||
|
||||
/// getCXXOverloadedOperator - If this name is the name of an
|
||||
/// overloadable operator in C++ (e.g., @c operator+), retrieve the
|
||||
/// kind of overloaded operator.
|
||||
OverloadedOperatorKind getCXXOverloadedOperator() const;
|
||||
|
||||
/// getObjCSelector - Get the Objective-C selector stored in this
|
||||
/// declaration name.
|
||||
Selector getObjCSelector() const;
|
||||
|
||||
/// getFETokenInfo/setFETokenInfo - The language front-end is
|
||||
/// allowed to associate arbitrary metadata with some kinds of
|
||||
/// declaration names, including normal identifiers and C++
|
||||
/// constructors, destructors, and conversion functions.
|
||||
template<typename T>
|
||||
T *getFETokenInfo() const { return static_cast<T*>(getFETokenInfoAsVoid()); }
|
||||
|
||||
void setFETokenInfo(void *T);
|
||||
|
||||
/// operator== - Determine whether the specified names are identical..
|
||||
friend bool operator==(DeclarationName LHS, DeclarationName RHS) {
|
||||
return LHS.Ptr == RHS.Ptr;
|
||||
}
|
||||
|
||||
/// operator!= - Determine whether the specified names are different.
|
||||
friend bool operator!=(DeclarationName LHS, DeclarationName RHS) {
|
||||
return LHS.Ptr != RHS.Ptr;
|
||||
}
|
||||
|
||||
static DeclarationName getEmptyMarker() {
|
||||
return DeclarationName(uintptr_t(-1));
|
||||
}
|
||||
|
||||
static DeclarationName getTombstoneMarker() {
|
||||
return DeclarationName(uintptr_t(-2));
|
||||
}
|
||||
};
|
||||
|
||||
/// Ordering on two declaration names. If both names are identifiers,
|
||||
/// this provides a lexicographical ordering.
|
||||
bool operator<(DeclarationName LHS, DeclarationName RHS);
|
||||
|
||||
/// Ordering on two declaration names. If both names are identifiers,
|
||||
/// this provides a lexicographical ordering.
|
||||
inline bool operator>(DeclarationName LHS, DeclarationName RHS) {
|
||||
return RHS < LHS;
|
||||
}
|
||||
|
||||
/// Ordering on two declaration names. If both names are identifiers,
|
||||
/// this provides a lexicographical ordering.
|
||||
inline bool operator<=(DeclarationName LHS, DeclarationName RHS) {
|
||||
return !(RHS < LHS);
|
||||
}
|
||||
|
||||
/// Ordering on two declaration names. If both names are identifiers,
|
||||
/// this provides a lexicographical ordering.
|
||||
inline bool operator>=(DeclarationName LHS, DeclarationName RHS) {
|
||||
return !(LHS < RHS);
|
||||
}
|
||||
|
||||
/// DeclarationNameTable - Used to store and retrieve DeclarationName
|
||||
/// instances for the various kinds of declaration names, e.g., normal
|
||||
/// identifiers, C++ constructor names, etc. This class contains
|
||||
/// uniqued versions of each of the C++ special names, which can be
|
||||
/// retrieved using its member functions (e.g.,
|
||||
/// getCXXConstructorName).
|
||||
class DeclarationNameTable {
|
||||
void *CXXSpecialNamesImpl; // Actually a FoldingSet<CXXSpecialName> *
|
||||
CXXOperatorIdName *CXXOperatorNames; // Operator names
|
||||
|
||||
DeclarationNameTable(const DeclarationNameTable&); // NONCOPYABLE
|
||||
DeclarationNameTable& operator=(const DeclarationNameTable&); // NONCOPYABLE
|
||||
|
||||
public:
|
||||
DeclarationNameTable();
|
||||
~DeclarationNameTable();
|
||||
|
||||
/// getIdentifier - Create a declaration name that is a simple
|
||||
/// identifier.
|
||||
DeclarationName getIdentifier(IdentifierInfo *ID) {
|
||||
return DeclarationName(ID);
|
||||
}
|
||||
|
||||
/// getCXXConstructorName - Returns the name of a C++ constructor
|
||||
/// for the given Type.
|
||||
DeclarationName getCXXConstructorName(QualType Ty) {
|
||||
return getCXXSpecialName(DeclarationName::CXXConstructorName, Ty);
|
||||
}
|
||||
|
||||
/// getCXXDestructorName - Returns the name of a C++ destructor
|
||||
/// for the given Type.
|
||||
DeclarationName getCXXDestructorName(QualType Ty) {
|
||||
return getCXXSpecialName(DeclarationName::CXXDestructorName, Ty);
|
||||
}
|
||||
|
||||
/// getCXXConversionFunctionName - Returns the name of a C++
|
||||
/// conversion function for the given Type.
|
||||
DeclarationName getCXXConversionFunctionName(QualType Ty) {
|
||||
return getCXXSpecialName(DeclarationName::CXXConversionFunctionName, Ty);
|
||||
}
|
||||
|
||||
/// getCXXSpecialName - Returns a declaration name for special kind
|
||||
/// of C++ name, e.g., for a constructor, destructor, or conversion
|
||||
/// function.
|
||||
DeclarationName getCXXSpecialName(DeclarationName::NameKind Kind,
|
||||
QualType Ty);
|
||||
|
||||
/// getCXXOperatorName - Get the name of the overloadable C++
|
||||
/// operator corresponding to Op.
|
||||
DeclarationName getCXXOperatorName(OverloadedOperatorKind Op);
|
||||
};
|
||||
|
||||
/// Insertion operator for diagnostics. This allows sending DeclarationName's
|
||||
/// into a diagnostic with <<.
|
||||
inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
|
||||
DeclarationName N) {
|
||||
DB.AddTaggedVal(N.getAsOpaqueInteger(),
|
||||
Diagnostic::ak_declarationname);
|
||||
return DB;
|
||||
}
|
||||
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
namespace llvm {
|
||||
/// Define DenseMapInfo so that DeclarationNames can be used as keys
|
||||
/// in DenseMap and DenseSets.
|
||||
template<>
|
||||
struct DenseMapInfo<clang::DeclarationName> {
|
||||
static inline clang::DeclarationName getEmptyKey() {
|
||||
return clang::DeclarationName::getEmptyMarker();
|
||||
}
|
||||
|
||||
static inline clang::DeclarationName getTombstoneKey() {
|
||||
return clang::DeclarationName::getTombstoneMarker();
|
||||
}
|
||||
|
||||
static unsigned getHashValue(clang::DeclarationName);
|
||||
|
||||
static inline bool
|
||||
isEqual(clang::DeclarationName LHS, clang::DeclarationName RHS) {
|
||||
return LHS == RHS;
|
||||
}
|
||||
|
||||
static inline bool isPod() { return true; }
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,846 +0,0 @@
|
||||
//===--- ExprCXX.h - Classes for representing expressions -------*- 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 Expr interface and subclasses for C++ expressions.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_EXPRCXX_H
|
||||
#define LLVM_CLANG_AST_EXPRCXX_H
|
||||
|
||||
#include "clang/Basic/TypeTraits.h"
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
class CXXConstructorDecl;
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// C++ Expressions.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
/// CXXOperatorCallExpr - Represents a call to an overloaded operator
|
||||
/// written using operator syntax, e.g., "x + y" or "*p". While
|
||||
/// semantically equivalent to a normal call, this AST node provides
|
||||
/// better information about the syntactic representation of the call.
|
||||
class CXXOperatorCallExpr : public CallExpr {
|
||||
public:
|
||||
CXXOperatorCallExpr(Expr *fn, Expr **args, unsigned numargs, QualType t,
|
||||
SourceLocation operatorloc)
|
||||
: CallExpr(CXXOperatorCallExprClass, fn, args, numargs, t, operatorloc) { }
|
||||
|
||||
/// getOperator - Returns the kind of overloaded operator that this
|
||||
/// expression refers to.
|
||||
OverloadedOperatorKind getOperator() const;
|
||||
|
||||
/// getOperatorLoc - Returns the location of the operator symbol in
|
||||
/// the expression. When @c getOperator()==OO_Call, this is the
|
||||
/// location of the right parentheses; when @c
|
||||
/// getOperator()==OO_Subscript, this is the location of the right
|
||||
/// bracket.
|
||||
SourceLocation getOperatorLoc() const { return getRParenLoc(); }
|
||||
|
||||
virtual SourceRange getSourceRange() const;
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CXXOperatorCallExprClass;
|
||||
}
|
||||
static bool classof(const CXXOperatorCallExpr *) { return true; }
|
||||
};
|
||||
|
||||
/// CXXMemberCallExpr - Represents a call to a member function that
|
||||
/// may be written either with member call syntax (e.g., "obj.func()"
|
||||
/// or "objptr->func()") or with normal function-call syntax
|
||||
/// ("func()") within a member function that ends up calling a member
|
||||
/// function. The callee in either case is a MemberExpr that contains
|
||||
/// both the object argument and the member function, while the
|
||||
/// arguments are the arguments within the parentheses (not including
|
||||
/// the object argument).
|
||||
class CXXMemberCallExpr : public CallExpr {
|
||||
public:
|
||||
CXXMemberCallExpr(Expr *fn, Expr **args, unsigned numargs, QualType t,
|
||||
SourceLocation rparenloc)
|
||||
: CallExpr(CXXMemberCallExprClass, fn, args, numargs, t, rparenloc) { }
|
||||
|
||||
/// getImplicitObjectArgument - Retrieves the implicit object
|
||||
/// argument for the member call. For example, in "x.f(5)", this
|
||||
/// operation would return "x".
|
||||
Expr *getImplicitObjectArgument();
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CXXMemberCallExprClass;
|
||||
}
|
||||
static bool classof(const CXXMemberCallExpr *) { return true; }
|
||||
};
|
||||
|
||||
/// CXXNamedCastExpr - Abstract class common to all of the C++ "named"
|
||||
/// casts, @c static_cast, @c dynamic_cast, @c reinterpret_cast, or @c
|
||||
/// const_cast.
|
||||
///
|
||||
/// This abstract class is inherited by all of the classes
|
||||
/// representing "named" casts, e.g., CXXStaticCastExpr,
|
||||
/// CXXDynamicCastExpr, CXXReinterpretCastExpr, and CXXConstCastExpr.
|
||||
class CXXNamedCastExpr : public ExplicitCastExpr {
|
||||
private:
|
||||
SourceLocation Loc; // the location of the casting op
|
||||
|
||||
protected:
|
||||
CXXNamedCastExpr(StmtClass SC, QualType ty, Expr *op, QualType writtenTy,
|
||||
SourceLocation l)
|
||||
: ExplicitCastExpr(SC, ty, op, writtenTy), Loc(l) {}
|
||||
|
||||
public:
|
||||
const char *getCastName() const;
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return SourceRange(Loc, getSubExpr()->getSourceRange().getEnd());
|
||||
}
|
||||
static bool classof(const Stmt *T) {
|
||||
switch (T->getStmtClass()) {
|
||||
case CXXNamedCastExprClass:
|
||||
case CXXStaticCastExprClass:
|
||||
case CXXDynamicCastExprClass:
|
||||
case CXXReinterpretCastExprClass:
|
||||
case CXXConstCastExprClass:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
static bool classof(const CXXNamedCastExpr *) { return true; }
|
||||
|
||||
virtual void EmitImpl(llvm::Serializer& S) const;
|
||||
static CXXNamedCastExpr *CreateImpl(llvm::Deserializer& D, ASTContext& C,
|
||||
StmtClass SC);
|
||||
};
|
||||
|
||||
/// CXXStaticCastExpr - A C++ @c static_cast expression (C++ [expr.static.cast]).
|
||||
///
|
||||
/// This expression node represents a C++ static cast, e.g.,
|
||||
/// @c static_cast<int>(1.0).
|
||||
class CXXStaticCastExpr : public CXXNamedCastExpr {
|
||||
public:
|
||||
CXXStaticCastExpr(QualType ty, Expr *op, QualType writtenTy, SourceLocation l)
|
||||
: CXXNamedCastExpr(CXXStaticCastExprClass, ty, op, writtenTy, l) {}
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CXXStaticCastExprClass;
|
||||
}
|
||||
static bool classof(const CXXStaticCastExpr *) { return true; }
|
||||
};
|
||||
|
||||
/// CXXDynamicCastExpr - A C++ @c dynamic_cast expression
|
||||
/// (C++ [expr.dynamic.cast]), which may perform a run-time check to
|
||||
/// determine how to perform the type cast.
|
||||
///
|
||||
/// This expression node represents a dynamic cast, e.g.,
|
||||
/// @c dynamic_cast<Derived*>(BasePtr).
|
||||
class CXXDynamicCastExpr : public CXXNamedCastExpr {
|
||||
public:
|
||||
CXXDynamicCastExpr(QualType ty, Expr *op, QualType writtenTy, SourceLocation l)
|
||||
: CXXNamedCastExpr(CXXDynamicCastExprClass, ty, op, writtenTy, l) {}
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CXXDynamicCastExprClass;
|
||||
}
|
||||
static bool classof(const CXXDynamicCastExpr *) { return true; }
|
||||
};
|
||||
|
||||
/// CXXReinterpretCastExpr - A C++ @c reinterpret_cast expression (C++
|
||||
/// [expr.reinterpret.cast]), which provides a differently-typed view
|
||||
/// of a value but performs no actual work at run time.
|
||||
///
|
||||
/// This expression node represents a reinterpret cast, e.g.,
|
||||
/// @c reinterpret_cast<int>(VoidPtr).
|
||||
class CXXReinterpretCastExpr : public CXXNamedCastExpr {
|
||||
public:
|
||||
CXXReinterpretCastExpr(QualType ty, Expr *op, QualType writtenTy,
|
||||
SourceLocation l)
|
||||
: CXXNamedCastExpr(CXXReinterpretCastExprClass, ty, op, writtenTy, l) {}
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CXXReinterpretCastExprClass;
|
||||
}
|
||||
static bool classof(const CXXReinterpretCastExpr *) { return true; }
|
||||
};
|
||||
|
||||
/// CXXConstCastExpr - A C++ @c const_cast expression (C++ [expr.const.cast]),
|
||||
/// which can remove type qualifiers but does not change the underlying value.
|
||||
///
|
||||
/// This expression node represents a const cast, e.g.,
|
||||
/// @c const_cast<char*>(PtrToConstChar).
|
||||
class CXXConstCastExpr : public CXXNamedCastExpr {
|
||||
public:
|
||||
CXXConstCastExpr(QualType ty, Expr *op, QualType writtenTy,
|
||||
SourceLocation l)
|
||||
: CXXNamedCastExpr(CXXConstCastExprClass, ty, op, writtenTy, l) {}
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CXXConstCastExprClass;
|
||||
}
|
||||
static bool classof(const CXXConstCastExpr *) { return true; }
|
||||
};
|
||||
|
||||
/// CXXBoolLiteralExpr - [C++ 2.13.5] C++ Boolean Literal.
|
||||
///
|
||||
class CXXBoolLiteralExpr : public Expr {
|
||||
bool Value;
|
||||
SourceLocation Loc;
|
||||
public:
|
||||
CXXBoolLiteralExpr(bool val, QualType Ty, SourceLocation l) :
|
||||
Expr(CXXBoolLiteralExprClass, Ty), Value(val), Loc(l) {}
|
||||
|
||||
bool getValue() const { return Value; }
|
||||
|
||||
virtual SourceRange getSourceRange() const { return SourceRange(Loc); }
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CXXBoolLiteralExprClass;
|
||||
}
|
||||
static bool classof(const CXXBoolLiteralExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
};
|
||||
|
||||
/// CXXTypeidExpr - A C++ @c typeid expression (C++ [expr.typeid]), which gets
|
||||
/// the type_info that corresponds to the supplied type, or the (possibly
|
||||
/// dynamic) type of the supplied expression.
|
||||
///
|
||||
/// This represents code like @c typeid(int) or @c typeid(*objPtr)
|
||||
class CXXTypeidExpr : public Expr {
|
||||
private:
|
||||
bool isTypeOp : 1;
|
||||
union {
|
||||
void *Ty;
|
||||
Stmt *Ex;
|
||||
} Operand;
|
||||
SourceRange Range;
|
||||
|
||||
public:
|
||||
CXXTypeidExpr(bool isTypeOp, void *op, QualType Ty, const SourceRange r) :
|
||||
Expr(CXXTypeidExprClass, Ty), isTypeOp(isTypeOp), Range(r) {
|
||||
if (isTypeOp)
|
||||
Operand.Ty = op;
|
||||
else
|
||||
// op was an Expr*, so cast it back to that to be safe
|
||||
Operand.Ex = static_cast<Stmt*>(op);
|
||||
}
|
||||
|
||||
bool isTypeOperand() const { return isTypeOp; }
|
||||
QualType getTypeOperand() const {
|
||||
assert(isTypeOperand() && "Cannot call getTypeOperand for typeid(expr)");
|
||||
return QualType::getFromOpaquePtr(Operand.Ty);
|
||||
}
|
||||
Expr* getExprOperand() const {
|
||||
assert(!isTypeOperand() && "Cannot call getExprOperand for typeid(type)");
|
||||
return static_cast<Expr*>(Operand.Ex);
|
||||
}
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return Range;
|
||||
}
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CXXTypeidExprClass;
|
||||
}
|
||||
static bool classof(const CXXTypeidExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
|
||||
virtual void EmitImpl(llvm::Serializer& S) const;
|
||||
static CXXTypeidExpr* CreateImpl(llvm::Deserializer& D, ASTContext& C);
|
||||
};
|
||||
|
||||
/// CXXThisExpr - Represents the "this" expression in C++, which is a
|
||||
/// pointer to the object on which the current member function is
|
||||
/// executing (C++ [expr.prim]p3). Example:
|
||||
///
|
||||
/// @code
|
||||
/// class Foo {
|
||||
/// public:
|
||||
/// void bar();
|
||||
/// void test() { this->bar(); }
|
||||
/// };
|
||||
/// @endcode
|
||||
class CXXThisExpr : public Expr {
|
||||
SourceLocation Loc;
|
||||
|
||||
public:
|
||||
CXXThisExpr(SourceLocation L, QualType Type)
|
||||
: Expr(CXXThisExprClass, Type), Loc(L) { }
|
||||
|
||||
virtual SourceRange getSourceRange() const { return SourceRange(Loc); }
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CXXThisExprClass;
|
||||
}
|
||||
static bool classof(const CXXThisExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
|
||||
virtual void EmitImpl(llvm::Serializer& S) const;
|
||||
static CXXThisExpr* CreateImpl(llvm::Deserializer& D, ASTContext& C);
|
||||
};
|
||||
|
||||
/// CXXThrowExpr - [C++ 15] C++ Throw Expression. This handles
|
||||
/// 'throw' and 'throw' assignment-expression. When
|
||||
/// assignment-expression isn't present, Op will be null.
|
||||
///
|
||||
class CXXThrowExpr : public Expr {
|
||||
Stmt *Op;
|
||||
SourceLocation ThrowLoc;
|
||||
public:
|
||||
// Ty is the void type which is used as the result type of the
|
||||
// exepression. The l is the location of the throw keyword. expr
|
||||
// can by null, if the optional expression to throw isn't present.
|
||||
CXXThrowExpr(Expr *expr, QualType Ty, SourceLocation l) :
|
||||
Expr(CXXThrowExprClass, Ty), Op(expr), ThrowLoc(l) {}
|
||||
const Expr *getSubExpr() const { return cast_or_null<Expr>(Op); }
|
||||
Expr *getSubExpr() { return cast_or_null<Expr>(Op); }
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
if (getSubExpr() == 0)
|
||||
return SourceRange(ThrowLoc, ThrowLoc);
|
||||
return SourceRange(ThrowLoc, getSubExpr()->getSourceRange().getEnd());
|
||||
}
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CXXThrowExprClass;
|
||||
}
|
||||
static bool classof(const CXXThrowExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
};
|
||||
|
||||
/// CXXDefaultArgExpr - C++ [dcl.fct.default]. This wraps up a
|
||||
/// function call argument that was created from the corresponding
|
||||
/// parameter's default argument, when the call did not explicitly
|
||||
/// supply arguments for all of the parameters.
|
||||
class CXXDefaultArgExpr : public Expr {
|
||||
ParmVarDecl *Param;
|
||||
public:
|
||||
// Param is the parameter whose default argument is used by this
|
||||
// expression.
|
||||
explicit CXXDefaultArgExpr(ParmVarDecl *param)
|
||||
: Expr(CXXDefaultArgExprClass,
|
||||
param->hasUnparsedDefaultArg()? param->getType().getNonReferenceType()
|
||||
: param->getDefaultArg()->getType()),
|
||||
Param(param) { }
|
||||
|
||||
// Retrieve the parameter that the argument was created from.
|
||||
const ParmVarDecl *getParam() const { return Param; }
|
||||
ParmVarDecl *getParam() { return Param; }
|
||||
|
||||
// Retrieve the actual argument to the function call.
|
||||
const Expr *getExpr() const { return Param->getDefaultArg(); }
|
||||
Expr *getExpr() { return Param->getDefaultArg(); }
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
// Default argument expressions have no representation in the
|
||||
// source, so they have an empty source range.
|
||||
return SourceRange();
|
||||
}
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CXXDefaultArgExprClass;
|
||||
}
|
||||
static bool classof(const CXXDefaultArgExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
|
||||
// Serialization
|
||||
virtual void EmitImpl(llvm::Serializer& S) const;
|
||||
static CXXDefaultArgExpr* CreateImpl(llvm::Deserializer& D,
|
||||
ASTContext& C);
|
||||
};
|
||||
|
||||
/// CXXFunctionalCastExpr - Represents an explicit C++ type conversion
|
||||
/// that uses "functional" notion (C++ [expr.type.conv]). Example: @c
|
||||
/// x = int(0.5);
|
||||
class CXXFunctionalCastExpr : public ExplicitCastExpr {
|
||||
SourceLocation TyBeginLoc;
|
||||
SourceLocation RParenLoc;
|
||||
public:
|
||||
CXXFunctionalCastExpr(QualType ty, QualType writtenTy,
|
||||
SourceLocation tyBeginLoc, Expr *castExpr,
|
||||
SourceLocation rParenLoc) :
|
||||
ExplicitCastExpr(CXXFunctionalCastExprClass, ty, castExpr, writtenTy),
|
||||
TyBeginLoc(tyBeginLoc), RParenLoc(rParenLoc) {}
|
||||
|
||||
SourceLocation getTypeBeginLoc() const { return TyBeginLoc; }
|
||||
SourceLocation getRParenLoc() const { return RParenLoc; }
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return SourceRange(TyBeginLoc, RParenLoc);
|
||||
}
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CXXFunctionalCastExprClass;
|
||||
}
|
||||
static bool classof(const CXXFunctionalCastExpr *) { return true; }
|
||||
|
||||
virtual void EmitImpl(llvm::Serializer& S) const;
|
||||
static CXXFunctionalCastExpr *
|
||||
CreateImpl(llvm::Deserializer& D, ASTContext& C);
|
||||
};
|
||||
|
||||
/// @brief Represents a C++ functional cast expression that builds a
|
||||
/// temporary object.
|
||||
///
|
||||
/// This expression type represents a C++ "functional" cast
|
||||
/// (C++[expr.type.conv]) with N != 1 arguments that invokes a
|
||||
/// constructor to build a temporary object. If N == 0 but no
|
||||
/// constructor will be called (because the functional cast is
|
||||
/// performing a value-initialized an object whose class type has no
|
||||
/// user-declared constructors), CXXZeroInitValueExpr will represent
|
||||
/// the functional cast. Finally, with N == 1 arguments the functional
|
||||
/// cast expression will be represented by CXXFunctionalCastExpr.
|
||||
/// Example:
|
||||
/// @code
|
||||
/// struct X { X(int, float); }
|
||||
///
|
||||
/// X create_X() {
|
||||
/// return X(1, 3.14f); // creates a CXXTemporaryObjectExpr
|
||||
/// };
|
||||
/// @endcode
|
||||
class CXXTemporaryObjectExpr : public Expr {
|
||||
SourceLocation TyBeginLoc;
|
||||
SourceLocation RParenLoc;
|
||||
CXXConstructorDecl *Constructor;
|
||||
Stmt **Args;
|
||||
unsigned NumArgs;
|
||||
|
||||
public:
|
||||
CXXTemporaryObjectExpr(CXXConstructorDecl *Cons, QualType writtenTy,
|
||||
SourceLocation tyBeginLoc, Expr **Args,
|
||||
unsigned NumArgs, SourceLocation rParenLoc);
|
||||
|
||||
~CXXTemporaryObjectExpr();
|
||||
|
||||
SourceLocation getTypeBeginLoc() const { return TyBeginLoc; }
|
||||
SourceLocation getRParenLoc() const { return RParenLoc; }
|
||||
|
||||
typedef ExprIterator arg_iterator;
|
||||
typedef ConstExprIterator const_arg_iterator;
|
||||
|
||||
arg_iterator arg_begin() { return Args; }
|
||||
arg_iterator arg_end() { return Args + NumArgs; }
|
||||
const_arg_iterator arg_begin() const { return Args; }
|
||||
const_arg_iterator arg_end() const { return Args + NumArgs; }
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return SourceRange(TyBeginLoc, RParenLoc);
|
||||
}
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CXXTemporaryObjectExprClass;
|
||||
}
|
||||
static bool classof(const CXXTemporaryObjectExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
|
||||
virtual void EmitImpl(llvm::Serializer& S) const;
|
||||
static CXXTemporaryObjectExpr *CreateImpl(llvm::Deserializer& D, ASTContext& C);
|
||||
};
|
||||
|
||||
/// CXXZeroInitValueExpr - [C++ 5.2.3p2]
|
||||
/// Expression "T()" which creates a value-initialized rvalue of type
|
||||
/// T, which is either a non-class type or a class type without any
|
||||
/// user-defined constructors.
|
||||
///
|
||||
class CXXZeroInitValueExpr : public Expr {
|
||||
SourceLocation TyBeginLoc;
|
||||
SourceLocation RParenLoc;
|
||||
|
||||
public:
|
||||
CXXZeroInitValueExpr(QualType ty, SourceLocation tyBeginLoc,
|
||||
SourceLocation rParenLoc ) :
|
||||
Expr(CXXZeroInitValueExprClass, ty),
|
||||
TyBeginLoc(tyBeginLoc), RParenLoc(rParenLoc) {}
|
||||
|
||||
SourceLocation getTypeBeginLoc() const { return TyBeginLoc; }
|
||||
SourceLocation getRParenLoc() const { return RParenLoc; }
|
||||
|
||||
/// @brief Whether this initialization expression was
|
||||
/// implicitly-generated.
|
||||
bool isImplicit() const {
|
||||
return TyBeginLoc.isInvalid() && RParenLoc.isInvalid();
|
||||
}
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return SourceRange(TyBeginLoc, RParenLoc);
|
||||
}
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CXXZeroInitValueExprClass;
|
||||
}
|
||||
static bool classof(const CXXZeroInitValueExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
|
||||
virtual void EmitImpl(llvm::Serializer& S) const;
|
||||
static CXXZeroInitValueExpr *
|
||||
CreateImpl(llvm::Deserializer& D, ASTContext& C);
|
||||
};
|
||||
|
||||
/// CXXConditionDeclExpr - Condition declaration of a if/switch/while/for
|
||||
/// statement, e.g: "if (int x = f()) {...}".
|
||||
/// The main difference with DeclRefExpr is that CXXConditionDeclExpr owns the
|
||||
/// decl that it references.
|
||||
///
|
||||
class CXXConditionDeclExpr : public DeclRefExpr {
|
||||
public:
|
||||
CXXConditionDeclExpr(SourceLocation startLoc,
|
||||
SourceLocation eqLoc, VarDecl *var)
|
||||
: DeclRefExpr(CXXConditionDeclExprClass, var,
|
||||
var->getType().getNonReferenceType(), startLoc) {}
|
||||
|
||||
virtual void Destroy(ASTContext& Ctx);
|
||||
|
||||
SourceLocation getStartLoc() const { return getLocation(); }
|
||||
|
||||
VarDecl *getVarDecl() { return cast<VarDecl>(getDecl()); }
|
||||
const VarDecl *getVarDecl() const { return cast<VarDecl>(getDecl()); }
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return SourceRange(getStartLoc(), getVarDecl()->getInit()->getLocEnd());
|
||||
}
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CXXConditionDeclExprClass;
|
||||
}
|
||||
static bool classof(const CXXConditionDeclExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
|
||||
// FIXME: Implement these.
|
||||
//virtual void EmitImpl(llvm::Serializer& S) const;
|
||||
//static CXXConditionDeclExpr *
|
||||
// CreateImpl(llvm::Deserializer& D, ASTContext& C);
|
||||
};
|
||||
|
||||
/// CXXNewExpr - A new expression for memory allocation and constructor calls,
|
||||
/// e.g: "new CXXNewExpr(foo)".
|
||||
class CXXNewExpr : public Expr {
|
||||
// Was the usage ::new, i.e. is the global new to be used?
|
||||
bool GlobalNew : 1;
|
||||
// Was the form (type-id) used? Otherwise, it was new-type-id.
|
||||
bool ParenTypeId : 1;
|
||||
// Is there an initializer? If not, built-ins are uninitialized, else they're
|
||||
// value-initialized.
|
||||
bool Initializer : 1;
|
||||
// Do we allocate an array? If so, the first SubExpr is the size expression.
|
||||
bool Array : 1;
|
||||
// The number of placement new arguments.
|
||||
unsigned NumPlacementArgs : 14;
|
||||
// The number of constructor arguments. This may be 1 even for non-class
|
||||
// types; use the pseudo copy constructor.
|
||||
unsigned NumConstructorArgs : 14;
|
||||
// Contains an optional array size expression, any number of optional
|
||||
// placement arguments, and any number of optional constructor arguments,
|
||||
// in that order.
|
||||
Stmt **SubExprs;
|
||||
// Points to the allocation function used.
|
||||
FunctionDecl *OperatorNew;
|
||||
// Points to the deallocation function used in case of error. May be null.
|
||||
FunctionDecl *OperatorDelete;
|
||||
// Points to the constructor used. Cannot be null if AllocType is a record;
|
||||
// it would still point at the default constructor (even an implicit one).
|
||||
// Must be null for all other types.
|
||||
CXXConstructorDecl *Constructor;
|
||||
|
||||
SourceLocation StartLoc;
|
||||
SourceLocation EndLoc;
|
||||
|
||||
// Deserialization constructor
|
||||
CXXNewExpr(QualType ty, bool globalNew, bool parenTypeId, bool initializer,
|
||||
bool array, unsigned numPlaceArgs, unsigned numConsArgs,
|
||||
Stmt **subExprs, FunctionDecl *operatorNew,
|
||||
FunctionDecl *operatorDelete, CXXConstructorDecl *constructor,
|
||||
SourceLocation startLoc, SourceLocation endLoc)
|
||||
: Expr(CXXNewExprClass, ty), GlobalNew(globalNew), ParenTypeId(parenTypeId),
|
||||
Initializer(initializer), Array(array), NumPlacementArgs(numPlaceArgs),
|
||||
NumConstructorArgs(numConsArgs), SubExprs(subExprs),
|
||||
OperatorNew(operatorNew), OperatorDelete(operatorDelete),
|
||||
Constructor(constructor), StartLoc(startLoc), EndLoc(endLoc)
|
||||
{ }
|
||||
public:
|
||||
CXXNewExpr(bool globalNew, FunctionDecl *operatorNew, Expr **placementArgs,
|
||||
unsigned numPlaceArgs, bool ParenTypeId, Expr *arraySize,
|
||||
CXXConstructorDecl *constructor, bool initializer,
|
||||
Expr **constructorArgs, unsigned numConsArgs,
|
||||
FunctionDecl *operatorDelete, QualType ty,
|
||||
SourceLocation startLoc, SourceLocation endLoc);
|
||||
~CXXNewExpr() {
|
||||
delete[] SubExprs;
|
||||
}
|
||||
|
||||
QualType getAllocatedType() const {
|
||||
assert(getType()->isPointerType());
|
||||
return getType()->getAsPointerType()->getPointeeType();
|
||||
}
|
||||
|
||||
FunctionDecl *getOperatorNew() const { return OperatorNew; }
|
||||
FunctionDecl *getOperatorDelete() const { return OperatorDelete; }
|
||||
CXXConstructorDecl *getConstructor() const { return Constructor; }
|
||||
|
||||
bool isArray() const { return Array; }
|
||||
Expr *getArraySize() {
|
||||
return Array ? cast<Expr>(SubExprs[0]) : 0;
|
||||
}
|
||||
const Expr *getArraySize() const {
|
||||
return Array ? cast<Expr>(SubExprs[0]) : 0;
|
||||
}
|
||||
|
||||
unsigned getNumPlacementArgs() const { return NumPlacementArgs; }
|
||||
Expr *getPlacementArg(unsigned i) {
|
||||
assert(i < NumPlacementArgs && "Index out of range");
|
||||
return cast<Expr>(SubExprs[Array + i]);
|
||||
}
|
||||
const Expr *getPlacementArg(unsigned i) const {
|
||||
assert(i < NumPlacementArgs && "Index out of range");
|
||||
return cast<Expr>(SubExprs[Array + i]);
|
||||
}
|
||||
|
||||
bool isGlobalNew() const { return GlobalNew; }
|
||||
bool isParenTypeId() const { return ParenTypeId; }
|
||||
bool hasInitializer() const { return Initializer; }
|
||||
|
||||
unsigned getNumConstructorArgs() const { return NumConstructorArgs; }
|
||||
Expr *getConstructorArg(unsigned i) {
|
||||
assert(i < NumConstructorArgs && "Index out of range");
|
||||
return cast<Expr>(SubExprs[Array + NumPlacementArgs + i]);
|
||||
}
|
||||
const Expr *getConstructorArg(unsigned i) const {
|
||||
assert(i < NumConstructorArgs && "Index out of range");
|
||||
return cast<Expr>(SubExprs[Array + NumPlacementArgs + i]);
|
||||
}
|
||||
|
||||
typedef ExprIterator arg_iterator;
|
||||
typedef ConstExprIterator const_arg_iterator;
|
||||
|
||||
arg_iterator placement_arg_begin() {
|
||||
return SubExprs + Array;
|
||||
}
|
||||
arg_iterator placement_arg_end() {
|
||||
return SubExprs + Array + getNumPlacementArgs();
|
||||
}
|
||||
const_arg_iterator placement_arg_begin() const {
|
||||
return SubExprs + Array;
|
||||
}
|
||||
const_arg_iterator placement_arg_end() const {
|
||||
return SubExprs + Array + getNumPlacementArgs();
|
||||
}
|
||||
|
||||
arg_iterator constructor_arg_begin() {
|
||||
return SubExprs + Array + getNumPlacementArgs();
|
||||
}
|
||||
arg_iterator constructor_arg_end() {
|
||||
return SubExprs + Array + getNumPlacementArgs() + getNumConstructorArgs();
|
||||
}
|
||||
const_arg_iterator constructor_arg_begin() const {
|
||||
return SubExprs + Array + getNumPlacementArgs();
|
||||
}
|
||||
const_arg_iterator constructor_arg_end() const {
|
||||
return SubExprs + Array + getNumPlacementArgs() + getNumConstructorArgs();
|
||||
}
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return SourceRange(StartLoc, EndLoc);
|
||||
}
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CXXNewExprClass;
|
||||
}
|
||||
static bool classof(const CXXNewExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
|
||||
virtual void EmitImpl(llvm::Serializer& S) const;
|
||||
static CXXNewExpr* CreateImpl(llvm::Deserializer& D, ASTContext& C);
|
||||
};
|
||||
|
||||
/// CXXDeleteExpr - A delete expression for memory deallocation and destructor
|
||||
/// calls, e.g. "delete[] pArray".
|
||||
class CXXDeleteExpr : public Expr {
|
||||
// Is this a forced global delete, i.e. "::delete"?
|
||||
bool GlobalDelete : 1;
|
||||
// Is this the array form of delete, i.e. "delete[]"?
|
||||
bool ArrayForm : 1;
|
||||
// Points to the operator delete overload that is used. Could be a member.
|
||||
FunctionDecl *OperatorDelete;
|
||||
// The pointer expression to be deleted.
|
||||
Stmt *Argument;
|
||||
// Location of the expression.
|
||||
SourceLocation Loc;
|
||||
public:
|
||||
CXXDeleteExpr(QualType ty, bool globalDelete, bool arrayForm,
|
||||
FunctionDecl *operatorDelete, Expr *arg, SourceLocation loc)
|
||||
: Expr(CXXDeleteExprClass, ty), GlobalDelete(globalDelete),
|
||||
ArrayForm(arrayForm), OperatorDelete(operatorDelete), Argument(arg),
|
||||
Loc(loc) { }
|
||||
|
||||
bool isGlobalDelete() const { return GlobalDelete; }
|
||||
bool isArrayForm() const { return ArrayForm; }
|
||||
|
||||
FunctionDecl *getOperatorDelete() const { return OperatorDelete; }
|
||||
|
||||
Expr *getArgument() { return cast<Expr>(Argument); }
|
||||
const Expr *getArgument() const { return cast<Expr>(Argument); }
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return SourceRange(Loc, Argument->getLocEnd());
|
||||
}
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CXXDeleteExprClass;
|
||||
}
|
||||
static bool classof(const CXXDeleteExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
|
||||
virtual void EmitImpl(llvm::Serializer& S) const;
|
||||
static CXXDeleteExpr * CreateImpl(llvm::Deserializer& D, ASTContext& C);
|
||||
};
|
||||
|
||||
/// CXXDependentNameExpr - Represents a dependent name in C++ for
|
||||
/// which we could not locate any definition. These names can only
|
||||
/// occur as in the example below, with an unqualified call to a
|
||||
/// function name whose arguments are dependent.
|
||||
/// @code
|
||||
/// template<typename T> void f(T x) {
|
||||
/// g(x); // g is a dependent name.
|
||||
/// }
|
||||
/// @endcode
|
||||
class CXXDependentNameExpr : public Expr {
|
||||
/// Name - The name that was present in the source code.
|
||||
IdentifierInfo *Name;
|
||||
|
||||
/// Loc - The location
|
||||
SourceLocation Loc;
|
||||
|
||||
public:
|
||||
CXXDependentNameExpr(IdentifierInfo *N, QualType T, SourceLocation L)
|
||||
: Expr(CXXDependentNameExprClass, T, true, true), Name(N), Loc(L) { }
|
||||
|
||||
/// getName - Retrieves the name that occurred in the source code.
|
||||
IdentifierInfo *getName() const { return Name; }
|
||||
|
||||
/// getLocation - Retrieves the location in the source code where
|
||||
/// the name occurred.
|
||||
SourceLocation getLocation() const { return Loc; }
|
||||
|
||||
virtual SourceRange getSourceRange() const { return SourceRange(Loc); }
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CXXDependentNameExprClass;
|
||||
}
|
||||
static bool classof(const CXXDependentNameExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
|
||||
virtual void EmitImpl(llvm::Serializer& S) const;
|
||||
static CXXDependentNameExpr *CreateImpl(llvm::Deserializer& D, ASTContext& C);
|
||||
};
|
||||
|
||||
/// UnaryTypeTraitExpr - A GCC or MS unary type trait, as used in the
|
||||
/// implementation of TR1/C++0x type trait templates.
|
||||
/// Example:
|
||||
/// __is_pod(int) == true
|
||||
/// __is_enum(std::string) == false
|
||||
class UnaryTypeTraitExpr : public Expr {
|
||||
/// UTT - The trait.
|
||||
UnaryTypeTrait UTT;
|
||||
|
||||
/// Loc - The location of the type trait keyword.
|
||||
SourceLocation Loc;
|
||||
|
||||
/// RParen - The location of the closing paren.
|
||||
SourceLocation RParen;
|
||||
|
||||
/// QueriedType - The type we're testing.
|
||||
QualType QueriedType;
|
||||
|
||||
public:
|
||||
UnaryTypeTraitExpr(SourceLocation loc, UnaryTypeTrait utt, QualType queried,
|
||||
SourceLocation rparen, QualType ty)
|
||||
: Expr(UnaryTypeTraitExprClass, ty, false, queried->isDependentType()),
|
||||
UTT(utt), Loc(loc), RParen(rparen), QueriedType(queried) { }
|
||||
|
||||
virtual SourceRange getSourceRange() const { return SourceRange(Loc, RParen);}
|
||||
|
||||
UnaryTypeTrait getTrait() const { return UTT; }
|
||||
|
||||
QualType getQueriedType() const { return QueriedType; }
|
||||
|
||||
bool Evaluate() const;
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == UnaryTypeTraitExprClass;
|
||||
}
|
||||
static bool classof(const UnaryTypeTraitExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
|
||||
virtual void EmitImpl(llvm::Serializer& S) const;
|
||||
static UnaryTypeTraitExpr *CreateImpl(llvm::Deserializer& D, ASTContext& C);
|
||||
};
|
||||
|
||||
/// QualifiedDeclRefExpr - A reference to a declared variable,
|
||||
/// function, enum, etc., that includes a qualification, e.g.,
|
||||
/// "N::foo".
|
||||
class QualifiedDeclRefExpr : public DeclRefExpr {
|
||||
/// NestedNameLoc - The location of the beginning of the
|
||||
/// nested-name-specifier that qualifies this declaration.
|
||||
SourceLocation NestedNameLoc;
|
||||
|
||||
public:
|
||||
QualifiedDeclRefExpr(NamedDecl *d, QualType t, SourceLocation l, bool TD,
|
||||
bool VD, SourceLocation nnl)
|
||||
: DeclRefExpr(QualifiedDeclRefExprClass, d, t, l, TD, VD),
|
||||
NestedNameLoc(nnl) { }
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return SourceRange(NestedNameLoc, getLocation());
|
||||
}
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == QualifiedDeclRefExprClass;
|
||||
}
|
||||
static bool classof(const QualifiedDeclRefExpr *) { return true; }
|
||||
|
||||
virtual void EmitImpl(llvm::Serializer& S) const;
|
||||
static QualifiedDeclRefExpr* CreateImpl(llvm::Deserializer& D, ASTContext& C);
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
@@ -1,452 +0,0 @@
|
||||
//===--- ExprObjC.h - Classes for representing ObjC expressions -*- 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 ExprObjC interface and subclasses.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_EXPROBJC_H
|
||||
#define LLVM_CLANG_AST_EXPROBJC_H
|
||||
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "clang/Basic/IdentifierTable.h"
|
||||
|
||||
namespace clang {
|
||||
class IdentifierInfo;
|
||||
class ASTContext;
|
||||
class ObjCMethodDecl;
|
||||
class ObjCPropertyDecl;
|
||||
|
||||
/// ObjCStringLiteral, used for Objective-C string literals
|
||||
/// i.e. @"foo".
|
||||
class ObjCStringLiteral : public Expr {
|
||||
StringLiteral *String;
|
||||
SourceLocation AtLoc;
|
||||
public:
|
||||
ObjCStringLiteral(StringLiteral *SL, QualType T, SourceLocation L)
|
||||
: Expr(ObjCStringLiteralClass, T), String(SL), AtLoc(L) {}
|
||||
|
||||
StringLiteral* getString() { return String; }
|
||||
|
||||
const StringLiteral* getString() const { return String; }
|
||||
|
||||
SourceLocation getAtLoc() const { return AtLoc; }
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return SourceRange(AtLoc, String->getLocEnd());
|
||||
}
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCStringLiteralClass;
|
||||
}
|
||||
static bool classof(const ObjCStringLiteral *) { return true; }
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
|
||||
virtual void EmitImpl(llvm::Serializer& S) const;
|
||||
static ObjCStringLiteral* CreateImpl(llvm::Deserializer& D, ASTContext& C);
|
||||
};
|
||||
|
||||
/// ObjCEncodeExpr, used for @encode in Objective-C.
|
||||
class ObjCEncodeExpr : public Expr {
|
||||
QualType EncType;
|
||||
SourceLocation AtLoc, RParenLoc;
|
||||
public:
|
||||
ObjCEncodeExpr(QualType T, QualType ET,
|
||||
SourceLocation at, SourceLocation rp)
|
||||
: Expr(ObjCEncodeExprClass, T), EncType(ET), AtLoc(at), RParenLoc(rp) {}
|
||||
|
||||
SourceLocation getAtLoc() const { return AtLoc; }
|
||||
SourceLocation getRParenLoc() const { return RParenLoc; }
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return SourceRange(AtLoc, RParenLoc);
|
||||
}
|
||||
|
||||
QualType getEncodedType() const { return EncType; }
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCEncodeExprClass;
|
||||
}
|
||||
static bool classof(const ObjCEncodeExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
|
||||
virtual void EmitImpl(llvm::Serializer& S) const;
|
||||
static ObjCEncodeExpr* CreateImpl(llvm::Deserializer& D, ASTContext& C);
|
||||
};
|
||||
|
||||
/// ObjCSelectorExpr used for @selector in Objective-C.
|
||||
class ObjCSelectorExpr : public Expr {
|
||||
Selector SelName;
|
||||
SourceLocation AtLoc, RParenLoc;
|
||||
public:
|
||||
ObjCSelectorExpr(QualType T, Selector selInfo,
|
||||
SourceLocation at, SourceLocation rp)
|
||||
: Expr(ObjCSelectorExprClass, T), SelName(selInfo),
|
||||
AtLoc(at), RParenLoc(rp) {}
|
||||
|
||||
Selector getSelector() const { return SelName; }
|
||||
|
||||
SourceLocation getAtLoc() const { return AtLoc; }
|
||||
SourceLocation getRParenLoc() const { return RParenLoc; }
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return SourceRange(AtLoc, RParenLoc);
|
||||
}
|
||||
|
||||
/// getNumArgs - Return the number of actual arguments to this call.
|
||||
unsigned getNumArgs() const { return SelName.getNumArgs(); }
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCSelectorExprClass;
|
||||
}
|
||||
static bool classof(const ObjCSelectorExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
|
||||
virtual void EmitImpl(llvm::Serializer& S) const;
|
||||
static ObjCSelectorExpr* CreateImpl(llvm::Deserializer& D, ASTContext& C);
|
||||
};
|
||||
|
||||
/// ObjCProtocolExpr used for protocol in Objective-C.
|
||||
class ObjCProtocolExpr : public Expr {
|
||||
ObjCProtocolDecl *Protocol;
|
||||
SourceLocation AtLoc, RParenLoc;
|
||||
public:
|
||||
ObjCProtocolExpr(QualType T, ObjCProtocolDecl *protocol,
|
||||
SourceLocation at, SourceLocation rp)
|
||||
: Expr(ObjCProtocolExprClass, T), Protocol(protocol),
|
||||
AtLoc(at), RParenLoc(rp) {}
|
||||
|
||||
ObjCProtocolDecl *getProtocol() const { return Protocol; }
|
||||
|
||||
SourceLocation getAtLoc() const { return AtLoc; }
|
||||
SourceLocation getRParenLoc() const { return RParenLoc; }
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return SourceRange(AtLoc, RParenLoc);
|
||||
}
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCProtocolExprClass;
|
||||
}
|
||||
static bool classof(const ObjCProtocolExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
|
||||
virtual void EmitImpl(llvm::Serializer& S) const;
|
||||
static ObjCProtocolExpr* CreateImpl(llvm::Deserializer& D, ASTContext& C);
|
||||
};
|
||||
|
||||
/// ObjCIvarRefExpr - A reference to an ObjC instance variable.
|
||||
class ObjCIvarRefExpr : public Expr {
|
||||
class ObjCIvarDecl *D;
|
||||
SourceLocation Loc;
|
||||
Stmt *Base;
|
||||
bool IsArrow:1; // True if this is "X->F", false if this is "X.F".
|
||||
bool IsFreeIvar:1; // True if ivar reference has no base (self assumed).
|
||||
|
||||
public:
|
||||
ObjCIvarRefExpr(ObjCIvarDecl *d,
|
||||
QualType t, SourceLocation l, Expr *base=0,
|
||||
bool arrow = false, bool freeIvar = false) :
|
||||
Expr(ObjCIvarRefExprClass, t), D(d),
|
||||
Loc(l), Base(base), IsArrow(arrow),
|
||||
IsFreeIvar(freeIvar) {}
|
||||
|
||||
ObjCIvarDecl *getDecl() { return D; }
|
||||
const ObjCIvarDecl *getDecl() const { return D; }
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return isFreeIvar() ? SourceRange(Loc)
|
||||
: SourceRange(getBase()->getLocStart(), Loc);
|
||||
}
|
||||
const Expr *getBase() const { return cast<Expr>(Base); }
|
||||
Expr *getBase() { return cast<Expr>(Base); }
|
||||
void setBase(Expr * base) { Base = base; }
|
||||
bool isArrow() const { return IsArrow; }
|
||||
bool isFreeIvar() const { return IsFreeIvar; }
|
||||
|
||||
SourceLocation getLocation() const { return Loc; }
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCIvarRefExprClass;
|
||||
}
|
||||
static bool classof(const ObjCIvarRefExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
|
||||
virtual void EmitImpl(llvm::Serializer& S) const;
|
||||
static ObjCIvarRefExpr* CreateImpl(llvm::Deserializer& D, ASTContext& C);
|
||||
};
|
||||
|
||||
/// ObjCPropertyRefExpr - A dot-syntax expression to access an ObjC
|
||||
/// property.
|
||||
///
|
||||
class ObjCPropertyRefExpr : public Expr {
|
||||
private:
|
||||
ObjCPropertyDecl *AsProperty;
|
||||
SourceLocation IdLoc;
|
||||
Stmt *Base;
|
||||
|
||||
public:
|
||||
ObjCPropertyRefExpr(ObjCPropertyDecl *PD, QualType t,
|
||||
SourceLocation l, Expr *base)
|
||||
: Expr(ObjCPropertyRefExprClass, t), AsProperty(PD), IdLoc(l), Base(base) {
|
||||
}
|
||||
ObjCPropertyDecl *getProperty() const {
|
||||
return AsProperty;
|
||||
}
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return SourceRange(getBase()->getLocStart(), IdLoc);
|
||||
}
|
||||
const Expr *getBase() const { return cast<Expr>(Base); }
|
||||
Expr *getBase() { return cast<Expr>(Base); }
|
||||
void setBase(Expr * base) { Base = base; }
|
||||
|
||||
SourceLocation getLocation() const { return IdLoc; }
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCPropertyRefExprClass;
|
||||
}
|
||||
static bool classof(const ObjCPropertyRefExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
|
||||
virtual void EmitImpl(llvm::Serializer& S) const;
|
||||
static ObjCPropertyRefExpr* CreateImpl(llvm::Deserializer& D, ASTContext& C);
|
||||
};
|
||||
|
||||
/// ObjCKVCRefExpr - A dot-syntax expression to access "implicit" properties
|
||||
/// (i.e. methods following the property naming convention). KVC stands for
|
||||
/// Key Value Encoding, a generic concept for accessing or setting a 'Key'
|
||||
/// value for an object.
|
||||
///
|
||||
|
||||
class ObjCKVCRefExpr : public Expr {
|
||||
private:
|
||||
|
||||
ObjCMethodDecl *Setter;
|
||||
ObjCMethodDecl *Getter;
|
||||
SourceLocation Loc;
|
||||
Stmt *Base;
|
||||
|
||||
public:
|
||||
ObjCKVCRefExpr(ObjCMethodDecl *getter,
|
||||
QualType t,
|
||||
ObjCMethodDecl *setter,
|
||||
SourceLocation l, Expr *base)
|
||||
: Expr(ObjCKVCRefExprClass, t), Setter(setter),
|
||||
Getter(getter), Loc(l), Base(base) {
|
||||
}
|
||||
|
||||
ObjCMethodDecl *getGetterMethod() const {
|
||||
return Getter;
|
||||
}
|
||||
ObjCMethodDecl *getSetterMethod() const {
|
||||
return Setter;
|
||||
}
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return SourceRange(getBase()->getLocStart(), Loc);
|
||||
}
|
||||
const Expr *getBase() const { return cast<Expr>(Base); }
|
||||
Expr *getBase() { return cast<Expr>(Base); }
|
||||
void setBase(Expr * base) { Base = base; }
|
||||
|
||||
SourceLocation getLocation() const { return Loc; }
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCKVCRefExprClass;
|
||||
}
|
||||
static bool classof(const ObjCKVCRefExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
|
||||
virtual void EmitImpl(llvm::Serializer& S) const;
|
||||
static ObjCKVCRefExpr* CreateImpl(llvm::Deserializer& D, ASTContext& C);
|
||||
};
|
||||
|
||||
class ObjCMessageExpr : public Expr {
|
||||
// SubExprs - The receiver and arguments of the message expression.
|
||||
Stmt **SubExprs;
|
||||
|
||||
// NumArgs - The number of arguments (not including the receiver) to the
|
||||
// message expression.
|
||||
unsigned NumArgs;
|
||||
|
||||
// A unigue name for this message.
|
||||
Selector SelName;
|
||||
|
||||
// A method prototype for this message (optional).
|
||||
// FIXME: Since method decls contain the selector, and most messages have a
|
||||
// prototype, consider devising a scheme for unifying SelName/MethodProto.
|
||||
ObjCMethodDecl *MethodProto;
|
||||
|
||||
SourceLocation LBracloc, RBracloc;
|
||||
|
||||
// Constants for indexing into SubExprs.
|
||||
enum { RECEIVER=0, ARGS_START=1 };
|
||||
|
||||
// Bit-swizziling flags.
|
||||
enum { IsInstMeth=0, IsClsMethDeclUnknown, IsClsMethDeclKnown, Flags=0x3 };
|
||||
unsigned getFlag() const { return (uintptr_t) SubExprs[RECEIVER] & Flags; }
|
||||
|
||||
// constructor used during deserialization
|
||||
ObjCMessageExpr(Selector selInfo, QualType retType,
|
||||
SourceLocation LBrac, SourceLocation RBrac,
|
||||
Stmt **subexprs, unsigned nargs)
|
||||
: Expr(ObjCMessageExprClass, retType), SubExprs(subexprs),
|
||||
NumArgs(nargs), SelName(selInfo), MethodProto(NULL),
|
||||
LBracloc(LBrac), RBracloc(RBrac) {}
|
||||
|
||||
public:
|
||||
/// This constructor is used to represent class messages where the
|
||||
/// ObjCInterfaceDecl* of the receiver is not known.
|
||||
ObjCMessageExpr(IdentifierInfo *clsName, Selector selInfo,
|
||||
QualType retType, ObjCMethodDecl *methDecl,
|
||||
SourceLocation LBrac, SourceLocation RBrac,
|
||||
Expr **ArgExprs, unsigned NumArgs);
|
||||
|
||||
/// This constructor is used to represent class messages where the
|
||||
/// ObjCInterfaceDecl* of the receiver is known.
|
||||
// FIXME: clsName should be typed to ObjCInterfaceType
|
||||
ObjCMessageExpr(ObjCInterfaceDecl *cls, Selector selInfo,
|
||||
QualType retType, ObjCMethodDecl *methDecl,
|
||||
SourceLocation LBrac, SourceLocation RBrac,
|
||||
Expr **ArgExprs, unsigned NumArgs);
|
||||
|
||||
// constructor for instance messages.
|
||||
ObjCMessageExpr(Expr *receiver, Selector selInfo,
|
||||
QualType retType, ObjCMethodDecl *methDecl,
|
||||
SourceLocation LBrac, SourceLocation RBrac,
|
||||
Expr **ArgExprs, unsigned NumArgs);
|
||||
|
||||
~ObjCMessageExpr() {
|
||||
delete [] SubExprs;
|
||||
}
|
||||
|
||||
/// getReceiver - Returns the receiver of the message expression.
|
||||
/// This can be NULL if the message is for class methods. For
|
||||
/// class methods, use getClassName.
|
||||
/// FIXME: need to handle/detect 'super' usage within a class method.
|
||||
Expr *getReceiver() {
|
||||
uintptr_t x = (uintptr_t) SubExprs[RECEIVER];
|
||||
return (x & Flags) == IsInstMeth ? (Expr*) x : 0;
|
||||
}
|
||||
const Expr *getReceiver() const {
|
||||
return const_cast<ObjCMessageExpr*>(this)->getReceiver();
|
||||
}
|
||||
|
||||
Selector getSelector() const { return SelName; }
|
||||
|
||||
const ObjCMethodDecl *getMethodDecl() const { return MethodProto; }
|
||||
ObjCMethodDecl *getMethodDecl() { return MethodProto; }
|
||||
|
||||
typedef std::pair<ObjCInterfaceDecl*, IdentifierInfo*> ClassInfo;
|
||||
|
||||
/// getClassInfo - For class methods, this returns both the ObjCInterfaceDecl*
|
||||
/// and IdentifierInfo* of the invoked class. Both can be NULL if this
|
||||
/// is an instance message, and the ObjCInterfaceDecl* can be NULL if none
|
||||
/// was available when this ObjCMessageExpr object was constructed.
|
||||
ClassInfo getClassInfo() const;
|
||||
|
||||
/// getClassName - For class methods, this returns the invoked class,
|
||||
/// and returns NULL otherwise. For instance methods, use getReceiver.
|
||||
IdentifierInfo *getClassName() const {
|
||||
return getClassInfo().second;
|
||||
}
|
||||
|
||||
|
||||
/// getNumArgs - Return the number of actual arguments to this call.
|
||||
unsigned getNumArgs() const { return NumArgs; }
|
||||
|
||||
/// getArg - Return the specified argument.
|
||||
Expr *getArg(unsigned Arg) {
|
||||
assert(Arg < NumArgs && "Arg access out of range!");
|
||||
return cast<Expr>(SubExprs[Arg+ARGS_START]);
|
||||
}
|
||||
const Expr *getArg(unsigned Arg) const {
|
||||
assert(Arg < NumArgs && "Arg access out of range!");
|
||||
return cast<Expr>(SubExprs[Arg+ARGS_START]);
|
||||
}
|
||||
/// setArg - Set the specified argument.
|
||||
void setArg(unsigned Arg, Expr *ArgExpr) {
|
||||
assert(Arg < NumArgs && "Arg access out of range!");
|
||||
SubExprs[Arg+ARGS_START] = ArgExpr;
|
||||
}
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return SourceRange(LBracloc, RBracloc);
|
||||
}
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCMessageExprClass;
|
||||
}
|
||||
static bool classof(const ObjCMessageExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
|
||||
typedef ExprIterator arg_iterator;
|
||||
typedef ConstExprIterator const_arg_iterator;
|
||||
|
||||
arg_iterator arg_begin() { return &SubExprs[ARGS_START]; }
|
||||
arg_iterator arg_end() { return &SubExprs[ARGS_START] + NumArgs; }
|
||||
const_arg_iterator arg_begin() const { return &SubExprs[ARGS_START]; }
|
||||
const_arg_iterator arg_end() const { return &SubExprs[ARGS_START] + NumArgs; }
|
||||
|
||||
// Serialization.
|
||||
virtual void EmitImpl(llvm::Serializer& S) const;
|
||||
static ObjCMessageExpr* CreateImpl(llvm::Deserializer& D, ASTContext& C);
|
||||
};
|
||||
|
||||
/// ObjCSuperExpr - Represents the "super" expression in Objective-C,
|
||||
/// which refers to the object on which the current method is executing.
|
||||
class ObjCSuperExpr : public Expr {
|
||||
SourceLocation Loc;
|
||||
|
||||
public:
|
||||
ObjCSuperExpr(SourceLocation L, QualType Type)
|
||||
: Expr(ObjCSuperExprClass, Type), Loc(L) { }
|
||||
|
||||
virtual SourceRange getSourceRange() const { return SourceRange(Loc); }
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == ObjCSuperExprClass;
|
||||
}
|
||||
static bool classof(const ObjCSuperExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
|
||||
virtual void EmitImpl(llvm::Serializer& S) const;
|
||||
static ObjCSuperExpr* CreateImpl(llvm::Deserializer& D, ASTContext& C);
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
@@ -1,24 +0,0 @@
|
||||
//===--- PPCBuiltins.def - PowerPC Builtin function database ----*- 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 PowerPC-specific builtin function database. Users of
|
||||
// this file must define the BUILTIN macro to make use of this information.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// FIXME: this needs to be the full list supported by GCC. Right now, I'm just
|
||||
// adding stuff on demand.
|
||||
|
||||
// The format of this database matches clang/AST/Builtins.def.
|
||||
|
||||
// This is just a placeholder, the types and attributes are wrong.
|
||||
BUILTIN(__builtin_altivec_abs_v4sf , "ii" , "nc")
|
||||
// FIXME: Obviously incomplete.
|
||||
|
||||
#undef BUILTIN
|
||||
@@ -1,34 +0,0 @@
|
||||
//===--- ParentMap.h - Mappings from Stmts to their Parents -----*- 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 ParentMap class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_PARENTMAP_H
|
||||
#define LLVM_CLANG_PARENTMAP_H
|
||||
|
||||
namespace clang {
|
||||
class Stmt;
|
||||
|
||||
class ParentMap {
|
||||
void* Impl;
|
||||
public:
|
||||
ParentMap(Stmt* ASTRoot);
|
||||
~ParentMap();
|
||||
|
||||
Stmt* getParent(Stmt*) const;
|
||||
|
||||
bool hasParent(Stmt* S) const {
|
||||
return getParent(S) != 0;
|
||||
}
|
||||
};
|
||||
|
||||
} // end clang namespace
|
||||
#endif
|
||||
@@ -1,31 +0,0 @@
|
||||
//===--- PrettyPrinter.h - Classes for aiding with AST printing -*- 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 PrinterHelper interface.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_PRETTY_PRINTER_H
|
||||
#define LLVM_CLANG_AST_PRETTY_PRINTER_H
|
||||
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
class Stmt;
|
||||
|
||||
class PrinterHelper {
|
||||
public:
|
||||
virtual ~PrinterHelper();
|
||||
virtual bool handledStmt(Stmt* E, llvm::raw_ostream& OS) = 0;
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
@@ -1,86 +0,0 @@
|
||||
//===--- RecordLayout.h - Layout information for a struct/union -*- 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 RecordLayout interface.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_LAYOUTINFO_H
|
||||
#define LLVM_CLANG_AST_LAYOUTINFO_H
|
||||
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
|
||||
namespace clang {
|
||||
class ASTContext;
|
||||
class RecordDecl;
|
||||
|
||||
/// ASTRecordLayout -
|
||||
/// This class contains layout information for one RecordDecl,
|
||||
/// which is a struct/union/class. The decl represented must be a definition,
|
||||
/// not a forward declaration.
|
||||
/// This class is also used to contain layout informaiton for one
|
||||
/// ObjCInterfaceDecl. FIXME - Find appropriate name.
|
||||
/// These objects are managed by ASTContext.
|
||||
class ASTRecordLayout {
|
||||
uint64_t Size; // Size of record in bits.
|
||||
unsigned Alignment; // Alignment of record in bits.
|
||||
unsigned FieldCount; // Number of fields
|
||||
uint64_t *FieldOffsets;
|
||||
friend class ASTContext;
|
||||
|
||||
ASTRecordLayout(uint64_t S = 0, unsigned A = 8)
|
||||
: Size(S), Alignment(A), FieldCount(0) {}
|
||||
~ASTRecordLayout() {
|
||||
delete [] FieldOffsets;
|
||||
}
|
||||
|
||||
/// Initialize record layout. N is the number of fields in this record.
|
||||
void InitializeLayout(unsigned N) {
|
||||
FieldCount = N;
|
||||
FieldOffsets = new uint64_t[N];
|
||||
}
|
||||
|
||||
/// Finalize record layout. Adjust record size based on the alignment.
|
||||
void FinalizeLayout() {
|
||||
// Finally, round the size of the record up to the alignment of the
|
||||
// record itself.
|
||||
Size = (Size + (Alignment-1)) & ~(Alignment-1);
|
||||
}
|
||||
|
||||
void SetFieldOffset(unsigned FieldNo, uint64_t Offset) {
|
||||
assert (FieldNo < FieldCount && "Invalid Field No");
|
||||
FieldOffsets[FieldNo] = Offset;
|
||||
}
|
||||
|
||||
void SetAlignment(unsigned A) { Alignment = A; }
|
||||
|
||||
/// LayoutField - Field layout. StructPacking is the specified
|
||||
/// packing alignment (maximum alignment) in bits to use for the
|
||||
/// structure, or 0 if no packing alignment is specified.
|
||||
void LayoutField(const FieldDecl *FD, unsigned FieldNo,
|
||||
bool IsUnion, unsigned StructPacking,
|
||||
ASTContext &Context);
|
||||
|
||||
ASTRecordLayout(const ASTRecordLayout&); // DO NOT IMPLEMENT
|
||||
void operator=(const ASTRecordLayout&); // DO NOT IMPLEMENT
|
||||
public:
|
||||
|
||||
unsigned getAlignment() const { return Alignment; }
|
||||
uint64_t getSize() const { return Size; }
|
||||
|
||||
uint64_t getFieldOffset(unsigned FieldNo) const {
|
||||
assert (FieldNo < FieldCount && "Invalid Field No");
|
||||
return FieldOffsets[FieldNo];
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,83 +0,0 @@
|
||||
//===--- StmtGraphTraits.h - Graph Traits for the class Stmt ----*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines a template specialization of llvm::GraphTraits to
|
||||
// treat ASTs (Stmt*) as graphs
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_STMT_GRAPHTRAITS_H
|
||||
#define LLVM_CLANG_AST_STMT_GRAPHTRAITS_H
|
||||
|
||||
#include "clang/AST/Stmt.h"
|
||||
#include "llvm/ADT/GraphTraits.h"
|
||||
#include "llvm/ADT/DepthFirstIterator.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
//template <typename T> struct GraphTraits;
|
||||
|
||||
|
||||
template <> struct GraphTraits<clang::Stmt*> {
|
||||
typedef clang::Stmt NodeType;
|
||||
typedef clang::Stmt::child_iterator ChildIteratorType;
|
||||
typedef llvm::df_iterator<clang::Stmt*> nodes_iterator;
|
||||
|
||||
static NodeType* getEntryNode(clang::Stmt* S) { return S; }
|
||||
|
||||
static inline ChildIteratorType child_begin(NodeType* N) {
|
||||
if (N) return N->child_begin();
|
||||
else return ChildIteratorType();
|
||||
}
|
||||
|
||||
static inline ChildIteratorType child_end(NodeType* N) {
|
||||
if (N) return N->child_end();
|
||||
else return ChildIteratorType();
|
||||
}
|
||||
|
||||
static nodes_iterator nodes_begin(clang::Stmt* S) {
|
||||
return df_begin(S);
|
||||
}
|
||||
|
||||
static nodes_iterator nodes_end(clang::Stmt* S) {
|
||||
return df_end(S);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <> struct GraphTraits<const clang::Stmt*> {
|
||||
typedef const clang::Stmt NodeType;
|
||||
typedef clang::Stmt::const_child_iterator ChildIteratorType;
|
||||
typedef llvm::df_iterator<const clang::Stmt*> nodes_iterator;
|
||||
|
||||
static NodeType* getEntryNode(const clang::Stmt* S) { return S; }
|
||||
|
||||
static inline ChildIteratorType child_begin(NodeType* N) {
|
||||
if (N) return N->child_begin();
|
||||
else return ChildIteratorType();
|
||||
}
|
||||
|
||||
static inline ChildIteratorType child_end(NodeType* N) {
|
||||
if (N) return N->child_end();
|
||||
else return ChildIteratorType();
|
||||
}
|
||||
|
||||
static nodes_iterator nodes_begin(const clang::Stmt* S) {
|
||||
return df_begin(S);
|
||||
}
|
||||
|
||||
static nodes_iterator nodes_end(const clang::Stmt* S) {
|
||||
return df_end(S);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
||||
@@ -1,144 +0,0 @@
|
||||
//===--- StmtIterator.h - Iterators for Statements ------------------------===//
|
||||
//
|
||||
// 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 StmtIterator and ConstStmtIterator classes.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_STMT_ITR_H
|
||||
#define LLVM_CLANG_AST_STMT_ITR_H
|
||||
|
||||
#include "llvm/ADT/iterator.h"
|
||||
#include <cassert>
|
||||
|
||||
namespace clang {
|
||||
|
||||
class Stmt;
|
||||
class Decl;
|
||||
class VariableArrayType;
|
||||
|
||||
class StmtIteratorBase {
|
||||
protected:
|
||||
enum { DeclMode = 0x1, SizeOfTypeVAMode = 0x2, DeclGroupMode = 0x3,
|
||||
Flags = 0x3 };
|
||||
|
||||
union { Stmt** stmt; Decl* decl; Decl** DGI; };
|
||||
uintptr_t RawVAPtr;
|
||||
Decl** DGE;
|
||||
|
||||
bool inDecl() const {
|
||||
return (RawVAPtr & Flags) == DeclMode;
|
||||
}
|
||||
|
||||
bool inDeclGroup() const {
|
||||
return (RawVAPtr & Flags) == DeclGroupMode;
|
||||
}
|
||||
|
||||
bool inSizeOfTypeVA() const {
|
||||
return (RawVAPtr & Flags) == SizeOfTypeVAMode;
|
||||
}
|
||||
|
||||
bool inStmt() const {
|
||||
return (RawVAPtr & Flags) == 0;
|
||||
}
|
||||
|
||||
VariableArrayType* getVAPtr() const {
|
||||
return reinterpret_cast<VariableArrayType*>(RawVAPtr & ~Flags);
|
||||
}
|
||||
|
||||
void setVAPtr(VariableArrayType* P) {
|
||||
assert (inDecl() || inDeclGroup() || inSizeOfTypeVA());
|
||||
RawVAPtr = reinterpret_cast<uintptr_t>(P) | (RawVAPtr & Flags);
|
||||
}
|
||||
|
||||
void NextDecl(bool ImmediateAdvance = true);
|
||||
bool HandleDecl(Decl* D);
|
||||
void NextVA();
|
||||
|
||||
Stmt*& GetDeclExpr() const;
|
||||
|
||||
StmtIteratorBase(Stmt** s) : stmt(s), RawVAPtr(0) {}
|
||||
StmtIteratorBase(Decl* d);
|
||||
StmtIteratorBase(VariableArrayType* t);
|
||||
StmtIteratorBase(Decl** dgi, Decl** dge);
|
||||
StmtIteratorBase() : stmt(NULL), RawVAPtr(0) {}
|
||||
};
|
||||
|
||||
|
||||
template <typename DERIVED, typename REFERENCE>
|
||||
class StmtIteratorImpl : public StmtIteratorBase,
|
||||
public std::iterator<std::forward_iterator_tag,
|
||||
REFERENCE, ptrdiff_t,
|
||||
REFERENCE, REFERENCE> {
|
||||
protected:
|
||||
StmtIteratorImpl(const StmtIteratorBase& RHS) : StmtIteratorBase(RHS) {}
|
||||
public:
|
||||
StmtIteratorImpl() {}
|
||||
StmtIteratorImpl(Stmt** s) : StmtIteratorBase(s) {}
|
||||
StmtIteratorImpl(Decl** dgi, Decl** dge) : StmtIteratorBase(dgi, dge) {}
|
||||
StmtIteratorImpl(Decl* d) : StmtIteratorBase(d) {}
|
||||
StmtIteratorImpl(VariableArrayType* t) : StmtIteratorBase(t) {}
|
||||
|
||||
DERIVED& operator++() {
|
||||
if (inDecl() || inDeclGroup()) {
|
||||
if (getVAPtr()) NextVA();
|
||||
else NextDecl();
|
||||
}
|
||||
else if (inSizeOfTypeVA())
|
||||
NextVA();
|
||||
else
|
||||
++stmt;
|
||||
|
||||
return static_cast<DERIVED&>(*this);
|
||||
}
|
||||
|
||||
DERIVED operator++(int) {
|
||||
DERIVED tmp = static_cast<DERIVED&>(*this);
|
||||
operator++();
|
||||
return tmp;
|
||||
}
|
||||
|
||||
bool operator==(const DERIVED& RHS) const {
|
||||
return stmt == RHS.stmt && RawVAPtr == RHS.RawVAPtr;
|
||||
}
|
||||
|
||||
bool operator!=(const DERIVED& RHS) const {
|
||||
return stmt != RHS.stmt || RawVAPtr != RHS.RawVAPtr;
|
||||
}
|
||||
|
||||
REFERENCE operator*() const {
|
||||
return (REFERENCE) (inStmt() ? *stmt : GetDeclExpr());
|
||||
}
|
||||
|
||||
REFERENCE operator->() const { return operator*(); }
|
||||
};
|
||||
|
||||
struct StmtIterator : public StmtIteratorImpl<StmtIterator,Stmt*&> {
|
||||
explicit StmtIterator() : StmtIteratorImpl<StmtIterator,Stmt*&>() {}
|
||||
|
||||
StmtIterator(Stmt** S) : StmtIteratorImpl<StmtIterator,Stmt*&>(S) {}
|
||||
StmtIterator(Decl** dgi, Decl** dge)
|
||||
: StmtIteratorImpl<StmtIterator,Stmt*&>(dgi, dge) {}
|
||||
|
||||
StmtIterator(VariableArrayType* t):StmtIteratorImpl<StmtIterator,Stmt*&>(t) {}
|
||||
StmtIterator(Decl* D) : StmtIteratorImpl<StmtIterator,Stmt*&>(D) {}
|
||||
};
|
||||
|
||||
struct ConstStmtIterator : public StmtIteratorImpl<ConstStmtIterator,
|
||||
const Stmt*> {
|
||||
explicit ConstStmtIterator() :
|
||||
StmtIteratorImpl<ConstStmtIterator,const Stmt*>() {}
|
||||
|
||||
ConstStmtIterator(const StmtIterator& RHS) :
|
||||
StmtIteratorImpl<ConstStmtIterator,const Stmt*>(RHS) {}
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
@@ -1,145 +0,0 @@
|
||||
//===-- StmtNodes.def - Metadata about Stmt AST nodes -----------*- 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 AST Node info database.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef FIRST_STMT
|
||||
#define FIRST_STMT(CLASS)
|
||||
#define LAST_STMT(CLASS)
|
||||
#endif
|
||||
|
||||
#ifndef FIRST_EXPR
|
||||
#define FIRST_EXPR(CLASS)
|
||||
#define LAST_EXPR(CLASS)
|
||||
#endif
|
||||
|
||||
// Normal Statements.
|
||||
STMT(NullStmt , Stmt)
|
||||
FIRST_STMT(NullStmt)
|
||||
STMT(CompoundStmt , Stmt)
|
||||
STMT(CaseStmt , SwitchCase)
|
||||
STMT(DefaultStmt , SwitchCase)
|
||||
STMT(LabelStmt , Stmt)
|
||||
STMT(IfStmt , Stmt)
|
||||
STMT(SwitchStmt , Stmt)
|
||||
STMT(WhileStmt , Stmt)
|
||||
STMT(DoStmt , Stmt)
|
||||
STMT(ForStmt , Stmt)
|
||||
STMT(GotoStmt , Stmt)
|
||||
STMT(IndirectGotoStmt, Stmt)
|
||||
STMT(ContinueStmt , Stmt)
|
||||
STMT(BreakStmt , Stmt)
|
||||
STMT(ReturnStmt , Stmt)
|
||||
STMT(DeclStmt , Stmt)
|
||||
STMT(SwitchCase , Stmt)
|
||||
|
||||
// GNU Stmt Extensions
|
||||
STMT(AsmStmt , Stmt)
|
||||
|
||||
// Obj-C statements
|
||||
STMT(ObjCAtTryStmt , Stmt)
|
||||
STMT(ObjCAtCatchStmt , Stmt)
|
||||
STMT(ObjCAtFinallyStmt , Stmt)
|
||||
STMT(ObjCAtThrowStmt , Stmt)
|
||||
STMT(ObjCAtSynchronizedStmt , Stmt)
|
||||
// Obj-C2 statements
|
||||
STMT(ObjCForCollectionStmt, Stmt)
|
||||
|
||||
// C++ statements
|
||||
STMT(CXXCatchStmt, Stmt)
|
||||
STMT(CXXTryStmt , Stmt)
|
||||
|
||||
LAST_STMT(CXXTryStmt)
|
||||
|
||||
// Expressions.
|
||||
STMT(Expr , Stmt)
|
||||
FIRST_EXPR(Expr)
|
||||
STMT(PredefinedExpr , Expr)
|
||||
STMT(DeclRefExpr , Expr)
|
||||
STMT(IntegerLiteral , Expr)
|
||||
STMT(FloatingLiteral , Expr)
|
||||
STMT(ImaginaryLiteral , Expr)
|
||||
STMT(StringLiteral , Expr)
|
||||
STMT(CharacterLiteral , Expr)
|
||||
STMT(ParenExpr , Expr)
|
||||
STMT(UnaryOperator , Expr)
|
||||
STMT(SizeOfAlignOfExpr , Expr)
|
||||
STMT(ArraySubscriptExpr , Expr)
|
||||
STMT(CallExpr , Expr)
|
||||
STMT(MemberExpr , Expr)
|
||||
STMT(CastExpr , Expr)
|
||||
STMT(BinaryOperator , Expr)
|
||||
STMT(CompoundAssignOperator, BinaryOperator)
|
||||
STMT(ConditionalOperator , Expr)
|
||||
STMT(ImplicitCastExpr , CastExpr)
|
||||
STMT(ExplicitCastExpr , CastExpr)
|
||||
STMT(CStyleCastExpr , ExplicitCastExpr)
|
||||
STMT(CompoundLiteralExpr , Expr)
|
||||
STMT(ExtVectorElementExpr , Expr)
|
||||
STMT(InitListExpr , Expr)
|
||||
STMT(DesignatedInitExpr , Expr)
|
||||
STMT(ImplicitValueInitExpr , Expr)
|
||||
STMT(VAArgExpr , Expr)
|
||||
|
||||
// GNU Extensions.
|
||||
STMT(AddrLabelExpr , Expr)
|
||||
STMT(StmtExpr , Expr)
|
||||
STMT(TypesCompatibleExpr , Expr)
|
||||
STMT(ChooseExpr , Expr)
|
||||
STMT(GNUNullExpr , Expr)
|
||||
|
||||
// C++ Expressions.
|
||||
STMT(CXXOperatorCallExpr , CallExpr)
|
||||
STMT(CXXMemberCallExpr , CallExpr)
|
||||
STMT(CXXNamedCastExpr , ExplicitCastExpr)
|
||||
STMT(CXXStaticCastExpr , CXXNamedCastExpr)
|
||||
STMT(CXXDynamicCastExpr , CXXNamedCastExpr)
|
||||
STMT(CXXReinterpretCastExpr , CXXNamedCastExpr)
|
||||
STMT(CXXConstCastExpr , CXXNamedCastExpr)
|
||||
STMT(CXXFunctionalCastExpr , ExplicitCastExpr)
|
||||
STMT(CXXTemporaryObjectExpr , Expr)
|
||||
STMT(CXXTypeidExpr , Expr)
|
||||
STMT(CXXBoolLiteralExpr , Expr)
|
||||
STMT(CXXThisExpr , Expr)
|
||||
STMT(CXXThrowExpr , Expr)
|
||||
STMT(CXXDefaultArgExpr , Expr)
|
||||
STMT(CXXZeroInitValueExpr , Expr)
|
||||
STMT(CXXConditionDeclExpr , DeclRefExpr)
|
||||
STMT(CXXNewExpr , Expr)
|
||||
STMT(CXXDeleteExpr , Expr)
|
||||
STMT(CXXDependentNameExpr , Expr)
|
||||
STMT(UnaryTypeTraitExpr , Expr)
|
||||
STMT(QualifiedDeclRefExpr , DeclRefExpr)
|
||||
|
||||
// Obj-C Expressions.
|
||||
STMT(ObjCStringLiteral , Expr)
|
||||
STMT(ObjCEncodeExpr , Expr)
|
||||
STMT(ObjCMessageExpr , Expr)
|
||||
STMT(ObjCSelectorExpr , Expr)
|
||||
STMT(ObjCProtocolExpr , Expr)
|
||||
STMT(ObjCIvarRefExpr , Expr)
|
||||
STMT(ObjCPropertyRefExpr , Expr)
|
||||
STMT(ObjCKVCRefExpr , Expr)
|
||||
STMT(ObjCSuperExpr , Expr)
|
||||
|
||||
// Clang Extensions.
|
||||
STMT(OverloadExpr , Expr)
|
||||
STMT(ShuffleVectorExpr , Expr)
|
||||
STMT(BlockExpr , Expr)
|
||||
STMT(BlockDeclRefExpr , Expr)
|
||||
|
||||
LAST_EXPR(BlockDeclRefExpr)
|
||||
|
||||
#undef STMT
|
||||
#undef FIRST_STMT
|
||||
#undef LAST_STMT
|
||||
#undef FIRST_EXPR
|
||||
#undef LAST_EXPR
|
||||
@@ -1,171 +0,0 @@
|
||||
//===--- StmtVisitor.h - Visitor for Stmt subclasses ------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the StmtVisitor interface.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_STMTVISITOR_H
|
||||
#define LLVM_CLANG_AST_STMTVISITOR_H
|
||||
|
||||
#include "clang/AST/ExprCXX.h"
|
||||
#include "clang/AST/ExprObjC.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
#define DISPATCH(NAME, CLASS) \
|
||||
return static_cast<ImplClass*>(this)->Visit ## NAME(static_cast<CLASS*>(S))
|
||||
|
||||
/// StmtVisitor - This class implements a simple visitor for Stmt subclasses.
|
||||
/// Since Expr derives from Stmt, this also includes support for visiting Exprs.
|
||||
template<typename ImplClass, typename RetTy=void>
|
||||
class StmtVisitor {
|
||||
public:
|
||||
RetTy Visit(Stmt *S) {
|
||||
|
||||
// If we have a binary expr, dispatch to the subcode of the binop. A smart
|
||||
// optimizer (e.g. LLVM) will fold this comparison into the switch stmt
|
||||
// below.
|
||||
if (BinaryOperator *BinOp = dyn_cast<BinaryOperator>(S)) {
|
||||
switch (BinOp->getOpcode()) {
|
||||
default: assert(0 && "Unknown binary operator!");
|
||||
case BinaryOperator::Mul: DISPATCH(BinMul, BinaryOperator);
|
||||
case BinaryOperator::Div: DISPATCH(BinDiv, BinaryOperator);
|
||||
case BinaryOperator::Rem: DISPATCH(BinRem, BinaryOperator);
|
||||
case BinaryOperator::Add: DISPATCH(BinAdd, BinaryOperator);
|
||||
case BinaryOperator::Sub: DISPATCH(BinSub, BinaryOperator);
|
||||
case BinaryOperator::Shl: DISPATCH(BinShl, BinaryOperator);
|
||||
case BinaryOperator::Shr: DISPATCH(BinShr, BinaryOperator);
|
||||
|
||||
case BinaryOperator::LT: DISPATCH(BinLT, BinaryOperator);
|
||||
case BinaryOperator::GT: DISPATCH(BinGT, BinaryOperator);
|
||||
case BinaryOperator::LE: DISPATCH(BinLE, BinaryOperator);
|
||||
case BinaryOperator::GE: DISPATCH(BinGE, BinaryOperator);
|
||||
case BinaryOperator::EQ: DISPATCH(BinEQ, BinaryOperator);
|
||||
case BinaryOperator::NE: DISPATCH(BinNE, BinaryOperator);
|
||||
|
||||
case BinaryOperator::And: DISPATCH(BinAnd, BinaryOperator);
|
||||
case BinaryOperator::Xor: DISPATCH(BinXor, BinaryOperator);
|
||||
case BinaryOperator::Or : DISPATCH(BinOr, BinaryOperator);
|
||||
case BinaryOperator::LAnd: DISPATCH(BinLAnd, BinaryOperator);
|
||||
case BinaryOperator::LOr : DISPATCH(BinLOr, BinaryOperator);
|
||||
case BinaryOperator::Assign: DISPATCH(BinAssign, BinaryOperator);
|
||||
case BinaryOperator::MulAssign:
|
||||
DISPATCH(BinMulAssign, CompoundAssignOperator);
|
||||
case BinaryOperator::DivAssign:
|
||||
DISPATCH(BinDivAssign, CompoundAssignOperator);
|
||||
case BinaryOperator::RemAssign:
|
||||
DISPATCH(BinRemAssign, CompoundAssignOperator);
|
||||
case BinaryOperator::AddAssign:
|
||||
DISPATCH(BinAddAssign, CompoundAssignOperator);
|
||||
case BinaryOperator::SubAssign:
|
||||
DISPATCH(BinSubAssign, CompoundAssignOperator);
|
||||
case BinaryOperator::ShlAssign:
|
||||
DISPATCH(BinShlAssign, CompoundAssignOperator);
|
||||
case BinaryOperator::ShrAssign:
|
||||
DISPATCH(BinShrAssign, CompoundAssignOperator);
|
||||
case BinaryOperator::AndAssign:
|
||||
DISPATCH(BinAndAssign, CompoundAssignOperator);
|
||||
case BinaryOperator::OrAssign:
|
||||
DISPATCH(BinOrAssign, CompoundAssignOperator);
|
||||
case BinaryOperator::XorAssign:
|
||||
DISPATCH(BinXorAssign, CompoundAssignOperator);
|
||||
case BinaryOperator::Comma: DISPATCH(BinComma, BinaryOperator);
|
||||
}
|
||||
} else if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(S)) {
|
||||
switch (UnOp->getOpcode()) {
|
||||
default: assert(0 && "Unknown unary operator!");
|
||||
case UnaryOperator::PostInc: DISPATCH(UnaryPostInc, UnaryOperator);
|
||||
case UnaryOperator::PostDec: DISPATCH(UnaryPostDec, UnaryOperator);
|
||||
case UnaryOperator::PreInc: DISPATCH(UnaryPreInc, UnaryOperator);
|
||||
case UnaryOperator::PreDec: DISPATCH(UnaryPreDec, UnaryOperator);
|
||||
case UnaryOperator::AddrOf: DISPATCH(UnaryAddrOf, UnaryOperator);
|
||||
case UnaryOperator::Deref: DISPATCH(UnaryDeref, UnaryOperator);
|
||||
case UnaryOperator::Plus: DISPATCH(UnaryPlus, UnaryOperator);
|
||||
case UnaryOperator::Minus: DISPATCH(UnaryMinus, UnaryOperator);
|
||||
case UnaryOperator::Not: DISPATCH(UnaryNot, UnaryOperator);
|
||||
case UnaryOperator::LNot: DISPATCH(UnaryLNot, UnaryOperator);
|
||||
case UnaryOperator::Real: DISPATCH(UnaryReal, UnaryOperator);
|
||||
case UnaryOperator::Imag: DISPATCH(UnaryImag, UnaryOperator);
|
||||
case UnaryOperator::Extension: DISPATCH(UnaryExtension, UnaryOperator);
|
||||
case UnaryOperator::OffsetOf: DISPATCH(UnaryOffsetOf, UnaryOperator);
|
||||
}
|
||||
}
|
||||
|
||||
// Top switch stmt: dispatch to VisitFooStmt for each FooStmt.
|
||||
switch (S->getStmtClass()) {
|
||||
default: assert(0 && "Unknown stmt kind!");
|
||||
#define STMT(CLASS, PARENT) \
|
||||
case Stmt::CLASS ## Class: DISPATCH(CLASS, CLASS);
|
||||
#include "clang/AST/StmtNodes.def"
|
||||
}
|
||||
}
|
||||
|
||||
// If the implementation chooses not to implement a certain visit method, fall
|
||||
// back on VisitExpr or whatever else is the superclass.
|
||||
#define STMT(CLASS, PARENT) \
|
||||
RetTy Visit ## CLASS(CLASS *S) { DISPATCH(PARENT, PARENT); }
|
||||
#include "clang/AST/StmtNodes.def"
|
||||
|
||||
// If the implementation doesn't implement binary operator methods, fall back
|
||||
// on VisitBinaryOperator.
|
||||
#define BINOP_FALLBACK(NAME) \
|
||||
RetTy VisitBin ## NAME(BinaryOperator *S) { \
|
||||
DISPATCH(BinaryOperator, BinaryOperator); \
|
||||
}
|
||||
BINOP_FALLBACK(Mul) BINOP_FALLBACK(Div) BINOP_FALLBACK(Rem)
|
||||
BINOP_FALLBACK(Add) BINOP_FALLBACK(Sub) BINOP_FALLBACK(Shl)
|
||||
BINOP_FALLBACK(Shr)
|
||||
|
||||
BINOP_FALLBACK(LT) BINOP_FALLBACK(GT) BINOP_FALLBACK(LE)
|
||||
BINOP_FALLBACK(GE) BINOP_FALLBACK(EQ) BINOP_FALLBACK(NE)
|
||||
BINOP_FALLBACK(And) BINOP_FALLBACK(Xor) BINOP_FALLBACK(Or)
|
||||
BINOP_FALLBACK(LAnd) BINOP_FALLBACK(LOr)
|
||||
|
||||
BINOP_FALLBACK(Assign)
|
||||
BINOP_FALLBACK(Comma)
|
||||
#undef BINOP_FALLBACK
|
||||
|
||||
// If the implementation doesn't implement compound assignment operator
|
||||
// methods, fall back on VisitCompoundAssignOperator.
|
||||
#define CAO_FALLBACK(NAME) \
|
||||
RetTy VisitBin ## NAME(CompoundAssignOperator *S) { \
|
||||
DISPATCH(CompoundAssignOperator, CompoundAssignOperator); \
|
||||
}
|
||||
CAO_FALLBACK(MulAssign) CAO_FALLBACK(DivAssign) CAO_FALLBACK(RemAssign)
|
||||
CAO_FALLBACK(AddAssign) CAO_FALLBACK(SubAssign) CAO_FALLBACK(ShlAssign)
|
||||
CAO_FALLBACK(ShrAssign) CAO_FALLBACK(AndAssign) CAO_FALLBACK(OrAssign)
|
||||
CAO_FALLBACK(XorAssign)
|
||||
#undef CAO_FALLBACK
|
||||
|
||||
// If the implementation doesn't implement unary operator methods, fall back
|
||||
// on VisitUnaryOperator.
|
||||
#define UNARYOP_FALLBACK(NAME) \
|
||||
RetTy VisitUnary ## NAME(UnaryOperator *S) { \
|
||||
DISPATCH(UnaryOperator, UnaryOperator); \
|
||||
}
|
||||
UNARYOP_FALLBACK(PostInc) UNARYOP_FALLBACK(PostDec)
|
||||
UNARYOP_FALLBACK(PreInc) UNARYOP_FALLBACK(PreDec)
|
||||
UNARYOP_FALLBACK(AddrOf) UNARYOP_FALLBACK(Deref)
|
||||
|
||||
UNARYOP_FALLBACK(Plus) UNARYOP_FALLBACK(Minus)
|
||||
UNARYOP_FALLBACK(Not) UNARYOP_FALLBACK(LNot)
|
||||
UNARYOP_FALLBACK(Real) UNARYOP_FALLBACK(Imag)
|
||||
UNARYOP_FALLBACK(Extension) UNARYOP_FALLBACK(OffsetOf)
|
||||
#undef UNARYOP_FALLBACK
|
||||
|
||||
// Base case, ignore it. :)
|
||||
RetTy VisitStmt(Stmt *Node) { return RetTy(); }
|
||||
};
|
||||
|
||||
#undef DISPATCH
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
@@ -1,38 +0,0 @@
|
||||
//===--- TargetBuiltins.h - Target specific builtin IDs -------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_TARGET_BUILTINS_H
|
||||
#define LLVM_CLANG_AST_TARGET_BUILTINS_H
|
||||
|
||||
#include "clang/AST/Builtins.h"
|
||||
#undef PPC
|
||||
|
||||
namespace clang {
|
||||
/// X86 builtins
|
||||
namespace X86 {
|
||||
enum {
|
||||
LastTIBuiltin = clang::Builtin::FirstTSBuiltin-1,
|
||||
#define BUILTIN(ID, TYPE, ATTRS) BI##ID,
|
||||
#include "X86Builtins.def"
|
||||
LastTSBuiltin
|
||||
};
|
||||
}
|
||||
|
||||
/// PPC builtins
|
||||
namespace PPC {
|
||||
enum {
|
||||
LastTIBuiltin = clang::Builtin::FirstTSBuiltin-1,
|
||||
#define BUILTIN(ID, TYPE, ATTRS) BI##ID,
|
||||
#include "PPCBuiltins.def"
|
||||
LastTSBuiltin
|
||||
};
|
||||
}
|
||||
} // end namespace clang.
|
||||
|
||||
#endif
|
||||
@@ -1,103 +0,0 @@
|
||||
//===--- TranslationUnit.h - Abstraction for Translation Units -----------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
// FIXME: This should eventually be moved out of the driver, or replaced
|
||||
// with its eventual successor.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_TRANSLATION_UNIT_H
|
||||
#define LLVM_CLANG_TRANSLATION_UNIT_H
|
||||
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "llvm/Bitcode/SerializationFwd.h"
|
||||
#include "llvm/System/Path.h"
|
||||
#include <string>
|
||||
|
||||
namespace clang {
|
||||
|
||||
class FileManager;
|
||||
class SourceManager;
|
||||
class TargetInfo;
|
||||
class IdentifierTable;
|
||||
class SelectorTable;
|
||||
class ASTContext;
|
||||
class Decl;
|
||||
class FileEntry;
|
||||
|
||||
class TranslationUnit {
|
||||
ASTContext* Context;
|
||||
bool OwnsMetaData;
|
||||
bool OwnsDecls;
|
||||
|
||||
// The default ctor is only invoked during deserialization.
|
||||
explicit TranslationUnit() : Context(NULL), OwnsMetaData(true),
|
||||
OwnsDecls(true) {}
|
||||
|
||||
public:
|
||||
explicit TranslationUnit(ASTContext& Ctx)
|
||||
: Context(&Ctx), OwnsMetaData(false), OwnsDecls(true) {}
|
||||
|
||||
void SetOwnsDecls(bool val) { OwnsDecls = val; }
|
||||
|
||||
~TranslationUnit();
|
||||
|
||||
const std::string& getSourceFile() const;
|
||||
|
||||
/// Emit - Emit the translation unit to an arbitray bitcode stream.
|
||||
void Emit(llvm::Serializer& S) const;
|
||||
|
||||
/// Create - Reconsititute a translation unit from a bitcode stream.
|
||||
static TranslationUnit* Create(llvm::Deserializer& D, FileManager& FMgr);
|
||||
|
||||
// Accessors
|
||||
const LangOptions& getLangOptions() const { return Context->getLangOptions();}
|
||||
|
||||
ASTContext& getContext() { return *Context; }
|
||||
const ASTContext& getContext() const { return *Context; }
|
||||
|
||||
typedef DeclContext::decl_iterator iterator;
|
||||
iterator begin() const {
|
||||
return Context->getTranslationUnitDecl()->decls_begin();
|
||||
}
|
||||
iterator end() const { return Context->getTranslationUnitDecl()->decls_end(); }
|
||||
};
|
||||
|
||||
/// EmitASTBitcodeFile - Emit a translation unit to a bitcode file.
|
||||
bool EmitASTBitcodeFile(const TranslationUnit& TU,
|
||||
const llvm::sys::Path& Filename);
|
||||
|
||||
bool EmitASTBitcodeFile(const TranslationUnit* TU,
|
||||
const llvm::sys::Path& Filename);
|
||||
|
||||
/// EmitASTBitcodeStream - Emit a translation unit to a std::ostream.
|
||||
bool EmitASTBitcodeStream(const TranslationUnit& TU,
|
||||
std::ostream& Stream);
|
||||
|
||||
bool EmitASTBitcodeStream(const TranslationUnit* TU,
|
||||
std::ostream& Stream);
|
||||
|
||||
/// EmitASTBitcodeBuffer - Emit a translation unit to a buffer.
|
||||
bool EmitASTBitcodeBuffer(const TranslationUnit& TU,
|
||||
std::vector<unsigned char>& Buffer);
|
||||
|
||||
bool EmitASTBitcodeBuffer(const TranslationUnit* TU,
|
||||
std::vector<unsigned char>& Buffer);
|
||||
|
||||
/// ReadASTBitcodeFile - Reconsitute a translation unit from a bitcode file.
|
||||
TranslationUnit* ReadASTBitcodeFile(const llvm::sys::Path& Filename,
|
||||
FileManager& FMgr);
|
||||
|
||||
/// ReadASTBitcodeBuffer - Reconsitute a translation unit from a buffer.
|
||||
TranslationUnit* ReadASTBitcodeBuffer(llvm::MemoryBuffer& MBuffer,
|
||||
FileManager& FMgr);
|
||||
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,63 +0,0 @@
|
||||
//===-------------- TypeOrdering.h - Total ordering for types -------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file provides a function objects and specializations that
|
||||
// allow QualType values to be sorted, used in std::maps, std::sets,
|
||||
// llvm::DenseMaps, and llvm::DenseSets.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_TYPE_ORDERING_H
|
||||
#define LLVM_CLANG_TYPE_ORDERING_H
|
||||
|
||||
#include "clang/AST/Type.h"
|
||||
#include <functional>
|
||||
|
||||
namespace clang {
|
||||
|
||||
/// QualTypeOrdering - Function object that provides a total ordering
|
||||
/// on QualType values.
|
||||
struct QualTypeOrdering : std::binary_function<QualType, QualType, bool> {
|
||||
bool operator()(QualType T1, QualType T2) const {
|
||||
return std::less<void*>()(T1.getAsOpaquePtr(), T2.getAsOpaquePtr());
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace llvm {
|
||||
template<class> struct DenseMapInfo;
|
||||
|
||||
template<> struct DenseMapInfo<clang::QualType> {
|
||||
static inline clang::QualType getEmptyKey() { return clang::QualType(); }
|
||||
|
||||
static inline clang::QualType getTombstoneKey() {
|
||||
using clang::QualType;
|
||||
return QualType::getFromOpaquePtr(reinterpret_cast<clang::Type *>(-1));
|
||||
}
|
||||
|
||||
static unsigned getHashValue(clang::QualType Val) {
|
||||
return (unsigned)((uintptr_t)Val.getAsOpaquePtr()) ^
|
||||
((unsigned)((uintptr_t)Val.getAsOpaquePtr() >> 9));
|
||||
}
|
||||
|
||||
static bool isEqual(clang::QualType LHS, clang::QualType RHS) {
|
||||
return LHS == RHS;
|
||||
}
|
||||
|
||||
static bool isPod() {
|
||||
// QualType isn't *technically* a POD type. However, we can get
|
||||
// away with calling it a POD type since its copy constructor,
|
||||
// copy assignment operator, and destructor are all trivial.
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,466 +0,0 @@
|
||||
//===--- X86Builtins.def - X86 Builtin function database --------*- 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 X86-specific builtin function database. Users of
|
||||
// this file must define the BUILTIN macro to make use of this information.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// FIXME: this needs to be the full list supported by GCC. Right now, I'm just
|
||||
// adding stuff on demand.
|
||||
|
||||
// The format of this database matches clang/AST/Builtins.def.
|
||||
|
||||
// FIXME: In GCC, these builtins are defined depending on whether support for
|
||||
// MMX/SSE/etc is turned on. We should do this too.
|
||||
|
||||
// FIXME: Ideally we would be able to pull this information from what
|
||||
// LLVM already knows about X86 builtins. We need to match the LLVM
|
||||
// definition anyway, since code generation will lower to the
|
||||
// intrinsic if one exists.
|
||||
|
||||
BUILTIN(__builtin_ia32_emms , "v", "")
|
||||
|
||||
// FIXME: Are these nothrow/const?
|
||||
|
||||
// SSE intrinsics.
|
||||
BUILTIN(__builtin_ia32_comieq, "iV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_comilt, "iV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_comile, "iV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_comigt, "iV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_comige, "iV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_comineq, "iV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_ucomieq, "iV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_ucomilt, "iV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_ucomile, "iV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_ucomigt, "iV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_ucomige, "iV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_ucomineq, "iV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_comisdeq, "iV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_comisdlt, "iV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_comisdle, "iV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_comisdgt, "iV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_comisdge, "iV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_comisdneq, "iV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_ucomisdeq, "iV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_ucomisdlt, "iV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_ucomisdle, "iV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_ucomisdgt, "iV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_ucomisdge, "iV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_ucomisdneq, "iV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_addps, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_subps, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_mulps, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_divps, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_addss, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_subss, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_mulss, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_divss, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_cmpeqps, "V4iV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_cmpltps, "V4iV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_cmpleps, "V4iV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_cmpgtps, "V4iV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_cmpgeps, "V4iV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_cmpunordps, "V4iV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_cmpneqps, "V4iV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_cmpnltps, "V4iV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_cmpnleps, "V4iV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_cmpngtps, "V4iV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_cmpngeps, "V4iV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_cmpordps, "V4iV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_cmpeqss, "V4iV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_cmpltss, "V4iV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_cmpless, "V4iV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_cmpunordss, "V4iV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_cmpneqss, "V4iV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_cmpnltss, "V4iV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_cmpnless, "V4iV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_cmpngtss, "V4iV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_cmpngess, "V4iV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_cmpordss, "V4iV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_minps, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_maxps, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_minss, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_maxss, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_andps, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_andnps, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_orps, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_xorps, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_movss, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_movhlps, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_movlhps, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_unpckhps, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_unpcklps, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_paddb, "V8cV8cV8c", "")
|
||||
BUILTIN(__builtin_ia32_paddw, "V4sV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_paddd, "V2iV2iV2i", "")
|
||||
BUILTIN(__builtin_ia32_paddq, "V1LLiV1LLiV1LLi", "")
|
||||
BUILTIN(__builtin_ia32_psubb, "V8cV8cV8c", "")
|
||||
BUILTIN(__builtin_ia32_psubw, "V4sV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_psubd, "V2iV2iV2i", "")
|
||||
BUILTIN(__builtin_ia32_psubq, "V1LLiV1LLiV1LLi", "")
|
||||
BUILTIN(__builtin_ia32_paddsb, "V8cV8cV8c", "")
|
||||
BUILTIN(__builtin_ia32_paddsw, "V4sV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_psubsb, "V8cV8cV8c", "")
|
||||
BUILTIN(__builtin_ia32_psubsw, "V4sV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_paddusb, "V8cV8cV8c", "")
|
||||
BUILTIN(__builtin_ia32_paddusw, "V4sV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_psubusb, "V8cV8cV8c", "")
|
||||
BUILTIN(__builtin_ia32_psubusw, "V4sV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_pmullw, "V4sV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_pmulhw, "V4sV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_pmulhuw, "V4sV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_pand, "V1LLiV1LLiV1LLi", "")
|
||||
BUILTIN(__builtin_ia32_pandn, "V1LLiV1LLiV1LLi", "")
|
||||
BUILTIN(__builtin_ia32_por, "V1LLiV1LLiV1LLi", "")
|
||||
BUILTIN(__builtin_ia32_pxor, "V1LLiV1LLiV1LLi", "")
|
||||
BUILTIN(__builtin_ia32_pavgb, "V8cV8cV8c", "")
|
||||
BUILTIN(__builtin_ia32_pavgw, "V4sV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_pcmpeqb, "V8cV8cV8c", "")
|
||||
BUILTIN(__builtin_ia32_pcmpeqw, "V4sV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_pcmpeqd, "V2iV2iV2i", "")
|
||||
BUILTIN(__builtin_ia32_pcmpgtb, "V8cV8cV8c", "")
|
||||
BUILTIN(__builtin_ia32_pcmpgtw, "V4sV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_pcmpgtd, "V2iV2iV2i", "")
|
||||
BUILTIN(__builtin_ia32_pmaxub, "V8cV8cV8c", "")
|
||||
BUILTIN(__builtin_ia32_pmaxsw, "V4sV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_pminub, "V8cV8cV8c", "")
|
||||
BUILTIN(__builtin_ia32_pminsw, "V4sV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_punpckhbw, "V8cV8cV8c", "")
|
||||
BUILTIN(__builtin_ia32_punpckhwd, "V4sV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_punpckhdq, "V2iV2iV2i", "")
|
||||
BUILTIN(__builtin_ia32_punpcklbw, "V8cV8cV8c", "")
|
||||
BUILTIN(__builtin_ia32_punpcklwd, "V4sV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_punpckldq, "V2iV2iV2i", "")
|
||||
BUILTIN(__builtin_ia32_addpd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_subpd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_mulpd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_divpd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_addsd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_subsd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_mulsd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_divsd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_cmpeqpd, "V4iV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_cmpltpd, "V4iV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_cmplepd, "V4iV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_cmpgtpd, "V4iV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_cmpgepd, "V4iV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_cmpunordpd, "V4iV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_cmpneqpd, "V4iV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_cmpnltpd, "V4iV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_cmpnlepd, "V4iV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_cmpngtpd, "V4iV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_cmpngepd, "V4iV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_cmpordpd, "V4iV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_cmpeqsd, "V4iV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_cmpltsd, "V4iV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_cmplesd, "V4iV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_cmpunordsd, "V4iV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_cmpneqsd, "V4iV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_cmpnltsd, "V4iV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_cmpnlesd, "V4iV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_cmpordsd, "V4iV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_minpd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_maxpd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_minsd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_maxsd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_andpd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_andnpd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_orpd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_xorpd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_movsd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_unpckhpd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_unpcklpd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_paddb128, "V16cV16cV16c", "")
|
||||
BUILTIN(__builtin_ia32_paddw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_paddd128, "V4iV4iV4i", "")
|
||||
BUILTIN(__builtin_ia32_paddq128, "V2LLiV2LLiV2LLi", "")
|
||||
BUILTIN(__builtin_ia32_psubb128, "V16cV16cV16c", "")
|
||||
BUILTIN(__builtin_ia32_psubw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_psubd128, "V4iV4iV4i", "")
|
||||
BUILTIN(__builtin_ia32_psubq128, "V2LLiV2LLiV2LLi", "")
|
||||
BUILTIN(__builtin_ia32_paddsb128, "V16cV16cV16c", "")
|
||||
BUILTIN(__builtin_ia32_paddsw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_psubsb128, "V16cV16cV16c", "")
|
||||
BUILTIN(__builtin_ia32_psubsw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_paddusb128, "V16cV16cV16c", "")
|
||||
BUILTIN(__builtin_ia32_paddusw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_psubusb128, "V16cV16cV16c", "")
|
||||
BUILTIN(__builtin_ia32_psubusw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_pmullw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_pmulhw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_pand128, "V2LLiV2LLiV2LLi", "")
|
||||
BUILTIN(__builtin_ia32_pandn128, "V2LLiV2LLiV2LLi", "")
|
||||
BUILTIN(__builtin_ia32_por128, "V2LLiV2LLiV2LLi", "")
|
||||
BUILTIN(__builtin_ia32_pxor128, "V2LLiV2LLiV2LLi", "")
|
||||
BUILTIN(__builtin_ia32_pavgb128, "V16cV16cV16c", "")
|
||||
BUILTIN(__builtin_ia32_pavgw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_pcmpeqb128, "V16cV16cV16c", "")
|
||||
BUILTIN(__builtin_ia32_pcmpeqw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_pcmpeqd128, "V4iV4iV4i", "")
|
||||
BUILTIN(__builtin_ia32_pcmpgtb128, "V16cV16cV16c", "")
|
||||
BUILTIN(__builtin_ia32_pcmpgtw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_pcmpgtd128, "V4iV4iV4i", "")
|
||||
BUILTIN(__builtin_ia32_pmaxub128, "V16cV16cV16c", "")
|
||||
BUILTIN(__builtin_ia32_pmaxsw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_pminub128, "V16cV16cV16c", "")
|
||||
BUILTIN(__builtin_ia32_pminsw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_punpckhbw128, "V16cV16cV16c", "")
|
||||
BUILTIN(__builtin_ia32_punpckhwd128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_punpckhdq128, "V4iV4iV4i", "")
|
||||
BUILTIN(__builtin_ia32_punpckhqdq128, "V2LLiV2LLiV2LLi", "")
|
||||
BUILTIN(__builtin_ia32_punpcklbw128, "V16cV16cV16c", "")
|
||||
BUILTIN(__builtin_ia32_punpcklwd128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_punpckldq128, "V4iV4iV4i", "")
|
||||
BUILTIN(__builtin_ia32_punpcklqdq128, "V2LLiV2LLiV2LLi", "")
|
||||
BUILTIN(__builtin_ia32_packsswb128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_packssdw128, "V4iV4iV4i", "")
|
||||
BUILTIN(__builtin_ia32_packuswb128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_pmulhuw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_addsubps, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_addsubpd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_haddps, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_haddpd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_hsubps, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_hsubpd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_phaddw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_phaddw, "V4sV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_phaddd128, "V4iV4iV4i", "")
|
||||
BUILTIN(__builtin_ia32_phaddd, "V2iV2iV2i", "")
|
||||
BUILTIN(__builtin_ia32_phaddsw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_phaddsw, "V4sV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_phsubw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_phsubw, "V4sV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_phsubd128, "V4iV4iV4i", "")
|
||||
BUILTIN(__builtin_ia32_phsubd, "V2iV2iV2i", "")
|
||||
BUILTIN(__builtin_ia32_phsubsw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_phsubsw, "V4sV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_pmaddubsw128, "V16cV16cV16c", "")
|
||||
BUILTIN(__builtin_ia32_pmaddubsw, "V8cV8cV8c", "")
|
||||
BUILTIN(__builtin_ia32_pmulhrsw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_pmulhrsw, "V4sV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_pshufb128, "V16cV16cV16c", "")
|
||||
BUILTIN(__builtin_ia32_pshufb, "V8cV8cV8c", "")
|
||||
BUILTIN(__builtin_ia32_psignb128, "V16cV16cV16c", "")
|
||||
BUILTIN(__builtin_ia32_psignb, "V8cV8cV8c", "")
|
||||
BUILTIN(__builtin_ia32_psignw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_psignw, "V4sV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_psignd128, "V4iV4iV4i", "")
|
||||
BUILTIN(__builtin_ia32_psignd, "V2iV2iV2i", "")
|
||||
BUILTIN(__builtin_ia32_pabsb128, "V16cV16c", "")
|
||||
BUILTIN(__builtin_ia32_pabsb, "V8cV8c", "")
|
||||
BUILTIN(__builtin_ia32_pabsw128, "V8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_pabsw, "V4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_pabsd128, "V4iV4i", "")
|
||||
BUILTIN(__builtin_ia32_pabsd, "V2iV2i", "")
|
||||
BUILTIN(__builtin_ia32_psllw, "V4sV4sV1LLi", "")
|
||||
BUILTIN(__builtin_ia32_pslld, "V2iV2iV1LLi", "")
|
||||
BUILTIN(__builtin_ia32_psllq, "V1LLiV1LLiV1LLi", "")
|
||||
BUILTIN(__builtin_ia32_psrlw, "V4sV4sV1LLi", "")
|
||||
BUILTIN(__builtin_ia32_psrld, "V2iV2iV1LLi", "")
|
||||
BUILTIN(__builtin_ia32_psrlq, "V1LLiV1LLiV1LLi", "")
|
||||
BUILTIN(__builtin_ia32_psraw, "V4sV4sV1LLi", "")
|
||||
BUILTIN(__builtin_ia32_psrad, "V2iV2iV1LLi", "")
|
||||
BUILTIN(__builtin_ia32_pshufw, "V4sV4si", "")
|
||||
BUILTIN(__builtin_ia32_pmaddwd, "V2iV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_packsswb, "V8cV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_packssdw, "V4sV2iV2i", "")
|
||||
BUILTIN(__builtin_ia32_packuswb, "V8cV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_ldmxcsr, "vUi", "")
|
||||
BUILTIN(__builtin_ia32_stmxcsr, "Ui", "")
|
||||
BUILTIN(__builtin_ia32_cvtpi2ps, "V4fV4fV2i", "")
|
||||
BUILTIN(__builtin_ia32_cvtps2pi, "V2iV4f", "")
|
||||
BUILTIN(__builtin_ia32_cvtsi2ss, "V4fV4fi", "")
|
||||
BUILTIN(__builtin_ia32_cvtsi642ss, "V4fV4fLLi", "")
|
||||
BUILTIN(__builtin_ia32_cvtss2si, "iV4f", "")
|
||||
BUILTIN(__builtin_ia32_cvtss2si64, "LLiV4f", "")
|
||||
BUILTIN(__builtin_ia32_cvttps2pi, "V2iV4f", "")
|
||||
BUILTIN(__builtin_ia32_cvttss2si, "iV4f", "")
|
||||
BUILTIN(__builtin_ia32_cvttss2si64, "LLiV4f", "")
|
||||
BUILTIN(__builtin_ia32_maskmovq, "vV8cV8cc*", "")
|
||||
BUILTIN(__builtin_ia32_loadups, "V4ffC*", "")
|
||||
BUILTIN(__builtin_ia32_storeups, "vf*V4f", "")
|
||||
BUILTIN(__builtin_ia32_loadhps, "V4fV4fV2i*", "")
|
||||
BUILTIN(__builtin_ia32_loadlps, "V4fV4fV2i*", "")
|
||||
BUILTIN(__builtin_ia32_storehps, "vV2i*V4f", "")
|
||||
BUILTIN(__builtin_ia32_storelps, "vV2i*V4f", "")
|
||||
BUILTIN(__builtin_ia32_movmskps, "iV4f", "")
|
||||
BUILTIN(__builtin_ia32_pmovmskb, "iV8c", "")
|
||||
BUILTIN(__builtin_ia32_movntps, "vf*V4f", "")
|
||||
BUILTIN(__builtin_ia32_movntq, "vV1LLi*V1LLi", "")
|
||||
BUILTIN(__builtin_ia32_sfence, "v", "")
|
||||
BUILTIN(__builtin_ia32_psadbw, "V4sV8cV8c", "")
|
||||
BUILTIN(__builtin_ia32_rcpps, "V4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_rcpss, "V4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_rsqrtps, "V4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_rsqrtss, "V4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_sqrtps, "V4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_sqrtss, "V4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_shufps, "V4fV4fV4fi", "")
|
||||
BUILTIN(__builtin_ia32_femms, "v", "")
|
||||
BUILTIN(__builtin_ia32_pavgusb, "V8cV8cV8c", "")
|
||||
BUILTIN(__builtin_ia32_pf2id, "V2iV2f", "")
|
||||
BUILTIN(__builtin_ia32_pfacc, "V2fV2fV2f", "")
|
||||
BUILTIN(__builtin_ia32_pfadd, "V2fV2fV2f", "")
|
||||
BUILTIN(__builtin_ia32_pfcmpeq, "V2iV2fV2f", "")
|
||||
BUILTIN(__builtin_ia32_pfcmpge, "V2iV2fV2f", "")
|
||||
BUILTIN(__builtin_ia32_pfcmpgt, "V2iV2fV2f", "")
|
||||
BUILTIN(__builtin_ia32_pfmax, "V2fV2fV2f", "")
|
||||
BUILTIN(__builtin_ia32_pfmin, "V2fV2fV2f", "")
|
||||
BUILTIN(__builtin_ia32_pfmul, "V2fV2fV2f", "")
|
||||
BUILTIN(__builtin_ia32_pfrcp, "V2fV2f", "")
|
||||
BUILTIN(__builtin_ia32_pfrcpit1, "V2fV2fV2f", "")
|
||||
BUILTIN(__builtin_ia32_pfrcpit2, "V2fV2fV2f", "")
|
||||
BUILTIN(__builtin_ia32_pfrsqrt, "V2fV2f", "")
|
||||
BUILTIN(__builtin_ia32_pfrsqit1, "V2fV2fV2f", "")
|
||||
BUILTIN(__builtin_ia32_pfsub, "V2fV2fV2f", "")
|
||||
BUILTIN(__builtin_ia32_pfsubr, "V2fV2fV2f", "")
|
||||
BUILTIN(__builtin_ia32_pi2fd, "V2fV2i", "")
|
||||
BUILTIN(__builtin_ia32_pmulhrw, "V4sV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_pf2iw, "V2iV2f", "")
|
||||
BUILTIN(__builtin_ia32_pfnacc, "V2fV2fV2f", "")
|
||||
BUILTIN(__builtin_ia32_pfpnacc, "V2fV2fV2f", "")
|
||||
BUILTIN(__builtin_ia32_pi2fw, "V2fV2i", "")
|
||||
BUILTIN(__builtin_ia32_pswapdsf, "V2fV2f", "")
|
||||
BUILTIN(__builtin_ia32_pswapdsi, "V2iV2i", "")
|
||||
BUILTIN(__builtin_ia32_maskmovdqu, "vV16cV16cc*", "")
|
||||
BUILTIN(__builtin_ia32_loadupd, "V2ddC*", "")
|
||||
BUILTIN(__builtin_ia32_storeupd, "vd*V2d", "")
|
||||
BUILTIN(__builtin_ia32_loadhpd, "V2dV2ddC*", "")
|
||||
BUILTIN(__builtin_ia32_loadlpd, "V2dV2ddC*", "")
|
||||
BUILTIN(__builtin_ia32_movmskpd, "iV2d", "")
|
||||
BUILTIN(__builtin_ia32_pmovmskb128, "iV16c", "")
|
||||
BUILTIN(__builtin_ia32_movnti, "vi*i", "")
|
||||
BUILTIN(__builtin_ia32_movntpd, "vd*V2d", "")
|
||||
BUILTIN(__builtin_ia32_movntdq, "vV2LLi*V2LLi", "")
|
||||
BUILTIN(__builtin_ia32_pshufd, "V4iV4ii", "")
|
||||
BUILTIN(__builtin_ia32_pshuflw, "V8sV8si", "")
|
||||
BUILTIN(__builtin_ia32_pshufhw, "V8sV8si", "")
|
||||
BUILTIN(__builtin_ia32_psadbw128, "V2LLiV16cV16c", "")
|
||||
BUILTIN(__builtin_ia32_sqrtpd, "V2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_sqrtsd, "V2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_shufpd, "V2dV2dV2di", "")
|
||||
BUILTIN(__builtin_ia32_cvtdq2pd, "V2dV4i", "")
|
||||
BUILTIN(__builtin_ia32_cvtdq2ps, "V4fV4i", "")
|
||||
BUILTIN(__builtin_ia32_cvtpd2dq, "V2LLiV2d", "")
|
||||
BUILTIN(__builtin_ia32_cvtpd2pi, "V2iV2d", "")
|
||||
BUILTIN(__builtin_ia32_cvtpd2ps, "V4fV2d", "")
|
||||
BUILTIN(__builtin_ia32_cvttpd2dq, "V4iV2d", "")
|
||||
BUILTIN(__builtin_ia32_cvttpd2pi, "V2iV2d", "")
|
||||
BUILTIN(__builtin_ia32_cvtpi2pd, "V2dV2i", "")
|
||||
BUILTIN(__builtin_ia32_cvtsd2si, "iV2d", "")
|
||||
BUILTIN(__builtin_ia32_cvttsd2si, "iV2d", "")
|
||||
BUILTIN(__builtin_ia32_cvtsd2si64, "LLiV2d", "")
|
||||
BUILTIN(__builtin_ia32_cvttsd2si64, "LLiV2d", "")
|
||||
BUILTIN(__builtin_ia32_cvtps2dq, "V4iV4f", "")
|
||||
BUILTIN(__builtin_ia32_cvtps2pd, "V2dV4f", "")
|
||||
BUILTIN(__builtin_ia32_cvttps2dq, "V4iV4f", "")
|
||||
BUILTIN(__builtin_ia32_cvtsi2sd, "V2dV2di", "")
|
||||
BUILTIN(__builtin_ia32_cvtsi642sd, "V2dV2dLLi", "")
|
||||
BUILTIN(__builtin_ia32_cvtsd2ss, "V4fV4fV2d", "")
|
||||
BUILTIN(__builtin_ia32_cvtss2sd, "V2dV2dV4f", "")
|
||||
BUILTIN(__builtin_ia32_clflush, "vvC*", "")
|
||||
BUILTIN(__builtin_ia32_lfence, "v", "")
|
||||
BUILTIN(__builtin_ia32_mfence, "v", "")
|
||||
BUILTIN(__builtin_ia32_loaddqu, "V16ccC*", "")
|
||||
BUILTIN(__builtin_ia32_storedqu, "vc*V16c", "")
|
||||
BUILTIN(__builtin_ia32_psllwi, "V4sV4si", "")
|
||||
BUILTIN(__builtin_ia32_pslldi, "V2iV2ii", "")
|
||||
BUILTIN(__builtin_ia32_psllqi, "V1LLiV1LLii", "")
|
||||
BUILTIN(__builtin_ia32_psrawi, "V4sV4si", "")
|
||||
BUILTIN(__builtin_ia32_psradi, "V2iV2ii", "")
|
||||
BUILTIN(__builtin_ia32_psrlwi, "V4sV4si", "")
|
||||
BUILTIN(__builtin_ia32_psrldi, "V2iV2ii", "")
|
||||
BUILTIN(__builtin_ia32_psrlqi, "V1LLiV1LLii", "")
|
||||
BUILTIN(__builtin_ia32_pmuludq, "V1LLiV2iV2i", "")
|
||||
BUILTIN(__builtin_ia32_pmuludq128, "V2LLiV4iV4i", "")
|
||||
BUILTIN(__builtin_ia32_psraw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_psrad128, "V4iV4iV4i", "")
|
||||
BUILTIN(__builtin_ia32_psrlw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_psrld128, "V4iV4iV4i", "")
|
||||
BUILTIN(__builtin_ia32_pslldqi128, "V2LLiV2LLii", "")
|
||||
BUILTIN(__builtin_ia32_psrldqi128, "V2LLiV2LLii", "")
|
||||
BUILTIN(__builtin_ia32_psrlq128, "V2LLiV2LLiV2LLi", "")
|
||||
BUILTIN(__builtin_ia32_psllw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_pslld128, "V4iV4iV4i", "")
|
||||
BUILTIN(__builtin_ia32_psllq128, "V2LLiV2LLiV2LLi", "")
|
||||
BUILTIN(__builtin_ia32_psllwi128, "V8sV8si", "")
|
||||
BUILTIN(__builtin_ia32_pslldi128, "V4iV4ii", "")
|
||||
BUILTIN(__builtin_ia32_psllqi128, "V2LLiV2LLii", "")
|
||||
BUILTIN(__builtin_ia32_psrlwi128, "V8sV8si", "")
|
||||
BUILTIN(__builtin_ia32_psrldi128, "V4iV4ii", "")
|
||||
BUILTIN(__builtin_ia32_psrlqi128, "V2LLiV2LLii", "")
|
||||
BUILTIN(__builtin_ia32_psrawi128, "V8sV8si", "")
|
||||
BUILTIN(__builtin_ia32_psradi128, "V4iV4ii", "")
|
||||
BUILTIN(__builtin_ia32_pmaddwd128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_monitor, "vv*UiUi", "")
|
||||
BUILTIN(__builtin_ia32_mwait, "vUiUi", "")
|
||||
BUILTIN(__builtin_ia32_movshdup, "V4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_movsldup, "V4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_lddqu, "V16ccC*", "")
|
||||
BUILTIN(__builtin_ia32_palignr128, "V2LLiV2LLiV2LLii", "")
|
||||
BUILTIN(__builtin_ia32_palignr, "V1LLiV1LLiV1LLis", "")
|
||||
BUILTIN(__builtin_ia32_vec_init_v2si, "V2iii", "")
|
||||
BUILTIN(__builtin_ia32_vec_init_v4hi, "V4sssss", "")
|
||||
BUILTIN(__builtin_ia32_vec_init_v8qi, "V8ccccccccc", "")
|
||||
BUILTIN(__builtin_ia32_vec_ext_v2df, "dV2di", "")
|
||||
BUILTIN(__builtin_ia32_vec_ext_v2di, "LLiV2LLii", "")
|
||||
BUILTIN(__builtin_ia32_vec_ext_v4sf, "fV4fi", "")
|
||||
BUILTIN(__builtin_ia32_vec_ext_v4si, "iV4ii", "")
|
||||
BUILTIN(__builtin_ia32_vec_ext_v8hi, "UsV8si", "")
|
||||
BUILTIN(__builtin_ia32_vec_ext_v4hi, "sV4si", "")
|
||||
BUILTIN(__builtin_ia32_vec_ext_v2si, "iV2ii", "")
|
||||
BUILTIN(__builtin_ia32_vec_set_v8hi, "V8sV8ssi", "")
|
||||
BUILTIN(__builtin_ia32_vec_set_v4hi, "V4sV4ssi", "")
|
||||
BUILTIN(__builtin_ia32_vec_set_v16qi, "V16cV16cii", "")
|
||||
BUILTIN(__builtin_ia32_vec_set_v4si, "V4iV4iii", "")
|
||||
BUILTIN(__builtin_ia32_vec_set_v2di, "V2LLiV2LLiLLii", "")
|
||||
BUILTIN(__builtin_ia32_insertps128, "V4fV4fV4fi", "")
|
||||
|
||||
BUILTIN(__builtin_ia32_movqv4si, "V4iV4i", "")
|
||||
BUILTIN(__builtin_ia32_loadlv4si, "V4iV2i*", "")
|
||||
BUILTIN(__builtin_ia32_storelv4si, "vV2i*V2LLi", "")
|
||||
|
||||
BUILTIN(__builtin_ia32_pblendvb128, "V16cV16cV16cV16c", "")
|
||||
BUILTIN(__builtin_ia32_pblendw128, "V8sV8sV8si", "")
|
||||
BUILTIN(__builtin_ia32_blendpd, "V2dV2dV2di", "")
|
||||
BUILTIN(__builtin_ia32_blendps, "V4fV4fV4fi", "")
|
||||
BUILTIN(__builtin_ia32_blendvpd, "V2dV2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_blendvps, "V4fV4fV4fV4f", "")
|
||||
|
||||
BUILTIN(__builtin_ia32_packusdw128, "V8sV4iV4i", "")
|
||||
BUILTIN(__builtin_ia32_pmaxsb128, "V16cV16cV16c", "")
|
||||
BUILTIN(__builtin_ia32_pmaxsd128, "V4iV4iV4i", "")
|
||||
BUILTIN(__builtin_ia32_pmaxud128, "V4iV4iV4i", "")
|
||||
BUILTIN(__builtin_ia32_pmaxuw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_pminsb128, "V16cV16cV16c", "")
|
||||
BUILTIN(__builtin_ia32_pminsd128, "V4iV4iV4i", "")
|
||||
BUILTIN(__builtin_ia32_pminud128, "V4iV4iV4i", "")
|
||||
BUILTIN(__builtin_ia32_pminuw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_pmovsxbd128, "V4iV16c", "")
|
||||
BUILTIN(__builtin_ia32_pmovsxbq128, "V2LLiV16c", "")
|
||||
BUILTIN(__builtin_ia32_pmovsxbw128, "V8sV16c", "")
|
||||
BUILTIN(__builtin_ia32_pmovsxdq128, "V2LLiV4i", "")
|
||||
BUILTIN(__builtin_ia32_pmovsxwd128, "V4iV8s", "")
|
||||
BUILTIN(__builtin_ia32_pmovsxwq128, "V2LLiV8s", "")
|
||||
BUILTIN(__builtin_ia32_pmovzxbd128, "V4iV16c", "")
|
||||
BUILTIN(__builtin_ia32_pmovzxbq128, "V2LLiV16c", "")
|
||||
BUILTIN(__builtin_ia32_pmovzxbw128, "V8sV16c", "")
|
||||
BUILTIN(__builtin_ia32_pmovzxdq128, "V2LLiV4i", "")
|
||||
BUILTIN(__builtin_ia32_pmovzxwd128, "V4iV8s", "")
|
||||
BUILTIN(__builtin_ia32_pmovzxwq128, "V2LLiV8s", "")
|
||||
BUILTIN(__builtin_ia32_pmuldq128, "V2LLiV4iV4i", "")
|
||||
BUILTIN(__builtin_ia32_pmulld128, "V4iV4iV4i", "")
|
||||
BUILTIN(__builtin_ia32_roundps, "V4fV4fi", "")
|
||||
BUILTIN(__builtin_ia32_roundss, "V4fV4fi", "")
|
||||
BUILTIN(__builtin_ia32_roundsd, "V2dV2di", "")
|
||||
BUILTIN(__builtin_ia32_roundpd, "V2dV2di", "")
|
||||
|
||||
|
||||
#undef BUILTIN
|
||||
@@ -1,119 +0,0 @@
|
||||
//===- LiveVariables.h - Live Variable Analysis for Source CFGs -*- C++ --*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements Live Variables analysis for source-level CFGs.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_LIVEVARIABLES_H
|
||||
#define LLVM_CLANG_LIVEVARIABLES_H
|
||||
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/Analysis/Support/BlkExprDeclBitVector.h"
|
||||
#include "clang/Analysis/FlowSensitive/DataflowValues.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
class Stmt;
|
||||
class DeclRefExpr;
|
||||
class SourceManager;
|
||||
|
||||
struct LiveVariables_ValueTypes {
|
||||
|
||||
struct ObserverTy;
|
||||
|
||||
// We keep dataflow state for declarations and block-level expressions;
|
||||
typedef StmtDeclBitVector_Types::ValTy ValTy;
|
||||
|
||||
// We need to keep track of both declarations and CFGBlock-level expressions,
|
||||
// (so that we don't explore such expressions twice). We also want
|
||||
// to compute liveness information for block-level expressions, since these
|
||||
// act as "temporary" values.
|
||||
|
||||
struct AnalysisDataTy : public StmtDeclBitVector_Types::AnalysisDataTy {
|
||||
ObserverTy* Observer;
|
||||
ValTy AlwaysLive;
|
||||
|
||||
AnalysisDataTy() : Observer(NULL) {}
|
||||
};
|
||||
|
||||
//===-----------------------------------------------------===//
|
||||
// ObserverTy - Observer for uninitialized values queries.
|
||||
//===-----------------------------------------------------===//
|
||||
|
||||
struct ObserverTy {
|
||||
virtual ~ObserverTy() {}
|
||||
|
||||
/// ObserveStmt - A callback invoked right before invoking the
|
||||
/// liveness transfer function on the given statement.
|
||||
virtual void ObserveStmt(Stmt* S, const AnalysisDataTy& AD,
|
||||
const ValTy& V) {}
|
||||
|
||||
virtual void ObserverKill(DeclRefExpr* DR) {}
|
||||
};
|
||||
};
|
||||
|
||||
class LiveVariables : public DataflowValues<LiveVariables_ValueTypes,
|
||||
dataflow::backward_analysis_tag> {
|
||||
|
||||
|
||||
public:
|
||||
typedef LiveVariables_ValueTypes::ObserverTy ObserverTy;
|
||||
|
||||
LiveVariables(ASTContext& Ctx, CFG& cfg);
|
||||
|
||||
/// IsLive - Return true if a variable is live at beginning of a
|
||||
/// specified block.
|
||||
bool isLive(const CFGBlock* B, const VarDecl* D) const;
|
||||
|
||||
/// IsLive - Returns true if a variable is live at the beginning of the
|
||||
/// the statement. This query only works if liveness information
|
||||
/// has been recorded at the statement level (see runOnAllBlocks), and
|
||||
/// only returns liveness information for block-level expressions.
|
||||
bool isLive(const Stmt* S, const VarDecl* D) const;
|
||||
|
||||
/// IsLive - Returns true the block-level expression "value" is live
|
||||
/// before the given block-level expression (see runOnAllBlocks).
|
||||
bool isLive(const Stmt* Loc, const Stmt* StmtVal) const;
|
||||
|
||||
/// IsLive - Return true if a variable is live according to the
|
||||
/// provided livness bitvector.
|
||||
bool isLive(const ValTy& V, const VarDecl* D) const;
|
||||
|
||||
/// dumpLiveness - Print to stderr the liveness information encoded
|
||||
/// by a specified bitvector.
|
||||
void dumpLiveness(const ValTy& V, SourceManager& M) const;
|
||||
|
||||
/// dumpBlockLiveness - Print to stderr the liveness information
|
||||
/// associated with each basic block.
|
||||
void dumpBlockLiveness(SourceManager& M) const;
|
||||
|
||||
/// getNumDecls - Return the number of variables (declarations) that
|
||||
/// whose liveness status is being tracked by the dataflow
|
||||
/// analysis.
|
||||
unsigned getNumDecls() const { return getAnalysisData().getNumDecls(); }
|
||||
|
||||
/// IntializeValues - This routine can perform extra initialization, but
|
||||
/// for LiveVariables this does nothing since all that logic is in
|
||||
/// the constructor.
|
||||
void InitializeValues(const CFG& cfg) {}
|
||||
|
||||
void runOnCFG(CFG& cfg);
|
||||
|
||||
/// runOnAllBlocks - Propagate the dataflow values once for each block,
|
||||
/// starting from the current dataflow values. 'recordStmtValues' indicates
|
||||
/// whether the method should store dataflow values per each individual
|
||||
/// block-level expression.
|
||||
void runOnAllBlocks(const CFG& cfg, ObserverTy* Obs,
|
||||
bool recordStmtValues=false);
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
@@ -1,74 +0,0 @@
|
||||
//===- UninitializedValues.h - unintialized values analysis ----*- C++ --*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file provides the interface for the Unintialized Values analysis,
|
||||
// a flow-sensitive analysis that detects when variable values are unintialized.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_UNITVALS_H
|
||||
#define LLVM_CLANG_UNITVALS_H
|
||||
|
||||
#include "clang/Analysis/Support/BlkExprDeclBitVector.h"
|
||||
#include "clang/Analysis/FlowSensitive/DataflowValues.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
class BlockVarDecl;
|
||||
class Expr;
|
||||
class DeclRefExpr;
|
||||
class VarDecl;
|
||||
|
||||
/// UninitializedValues_ValueTypes - Utility class to wrap type declarations
|
||||
/// for dataflow values and dataflow analysis state for the
|
||||
/// Unitialized Values analysis.
|
||||
class UninitializedValues_ValueTypes {
|
||||
public:
|
||||
|
||||
struct ObserverTy;
|
||||
|
||||
struct AnalysisDataTy : public StmtDeclBitVector_Types::AnalysisDataTy {
|
||||
AnalysisDataTy() : Observer(NULL), FullUninitTaint(true) {}
|
||||
virtual ~AnalysisDataTy() {};
|
||||
|
||||
ObserverTy* Observer;
|
||||
bool FullUninitTaint;
|
||||
};
|
||||
|
||||
typedef StmtDeclBitVector_Types::ValTy ValTy;
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// ObserverTy - Observer for querying DeclRefExprs that use an uninitalized
|
||||
// value.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
struct ObserverTy {
|
||||
virtual ~ObserverTy();
|
||||
virtual void ObserveDeclRefExpr(ValTy& Val, AnalysisDataTy& AD,
|
||||
DeclRefExpr* DR, VarDecl* VD) = 0;
|
||||
};
|
||||
};
|
||||
|
||||
/// UninitializedValues - Objects of this class encapsulate dataflow analysis
|
||||
/// information regarding what variable declarations in a function are
|
||||
/// potentially unintialized.
|
||||
class UninitializedValues :
|
||||
public DataflowValues<UninitializedValues_ValueTypes> {
|
||||
public:
|
||||
typedef UninitializedValues_ValueTypes::ObserverTy ObserverTy;
|
||||
|
||||
UninitializedValues(CFG &cfg) { getAnalysisData().setCFG(cfg); }
|
||||
|
||||
/// IntializeValues - Create initial dataflow values and meta data for
|
||||
/// a given CFG. This is intended to be called by the dataflow solver.
|
||||
void InitializeValues(const CFG& cfg);
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
#endif
|
||||
@@ -1,27 +0,0 @@
|
||||
//===--- DiagnosticAnalysis.h - Diagnostics for libanalysis -----*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_DIAGNOSTICANALYSIS_H
|
||||
#define LLVM_CLANG_DIAGNOSTICANALYSIS_H
|
||||
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
|
||||
namespace clang {
|
||||
namespace diag {
|
||||
enum {
|
||||
#define DIAG(ENUM,FLAGS,DESC) ENUM,
|
||||
#define ANALYSISSTART
|
||||
#include "clang/Basic/DiagnosticAnalysisKinds.def"
|
||||
#undef DIAG
|
||||
NUM_BUILTIN_ANALYSIS_DIAGNOSTICS
|
||||
};
|
||||
} // end namespace diag
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
@@ -1,291 +0,0 @@
|
||||
//===--- DataflowSolver.h - Skeleton Dataflow Analysis Code -----*- 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 skeleton code for implementing dataflow analyses.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSES_DATAFLOW_SOLVER
|
||||
#define LLVM_CLANG_ANALYSES_DATAFLOW_SOLVER
|
||||
|
||||
#include "clang/AST/CFG.h"
|
||||
#include "clang/Analysis/ProgramPoint.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "functional" // STL
|
||||
|
||||
namespace clang {
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// DataflowWorkListTy - Data structure representing the worklist used for
|
||||
/// dataflow algorithms.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
class DataflowWorkListTy {
|
||||
typedef llvm::SmallPtrSet<const CFGBlock*,20> BlockSet;
|
||||
BlockSet wlist;
|
||||
public:
|
||||
/// enqueue - Add a block to the worklist. Blocks already on the
|
||||
/// worklist are not added a second time.
|
||||
void enqueue(const CFGBlock* B) { wlist.insert(B); }
|
||||
|
||||
/// dequeue - Remove a block from the worklist.
|
||||
const CFGBlock* dequeue() {
|
||||
assert (!wlist.empty());
|
||||
const CFGBlock* B = *wlist.begin();
|
||||
wlist.erase(B);
|
||||
return B;
|
||||
}
|
||||
|
||||
/// isEmpty - Return true if the worklist is empty.
|
||||
bool isEmpty() const { return wlist.empty(); }
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// BlockItrTraits - Traits classes that allow transparent iteration
|
||||
// over successors/predecessors of a block depending on the direction
|
||||
// of our dataflow analysis.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace dataflow {
|
||||
template<typename Tag> struct ItrTraits {};
|
||||
|
||||
template <> struct ItrTraits<forward_analysis_tag> {
|
||||
typedef CFGBlock::const_pred_iterator PrevBItr;
|
||||
typedef CFGBlock::const_succ_iterator NextBItr;
|
||||
typedef CFGBlock::const_iterator StmtItr;
|
||||
|
||||
static PrevBItr PrevBegin(const CFGBlock* B) { return B->pred_begin(); }
|
||||
static PrevBItr PrevEnd(const CFGBlock* B) { return B->pred_end(); }
|
||||
|
||||
static NextBItr NextBegin(const CFGBlock* B) { return B->succ_begin(); }
|
||||
static NextBItr NextEnd(const CFGBlock* B) { return B->succ_end(); }
|
||||
|
||||
static StmtItr StmtBegin(const CFGBlock* B) { return B->begin(); }
|
||||
static StmtItr StmtEnd(const CFGBlock* B) { return B->end(); }
|
||||
|
||||
static BlockEdge PrevEdge(const CFGBlock* B, const CFGBlock* Prev) {
|
||||
return BlockEdge(Prev, B);
|
||||
}
|
||||
|
||||
static BlockEdge NextEdge(const CFGBlock* B, const CFGBlock* Next) {
|
||||
return BlockEdge(B, Next);
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct ItrTraits<backward_analysis_tag> {
|
||||
typedef CFGBlock::const_succ_iterator PrevBItr;
|
||||
typedef CFGBlock::const_pred_iterator NextBItr;
|
||||
typedef CFGBlock::const_reverse_iterator StmtItr;
|
||||
|
||||
static PrevBItr PrevBegin(const CFGBlock* B) { return B->succ_begin(); }
|
||||
static PrevBItr PrevEnd(const CFGBlock* B) { return B->succ_end(); }
|
||||
|
||||
static NextBItr NextBegin(const CFGBlock* B) { return B->pred_begin(); }
|
||||
static NextBItr NextEnd(const CFGBlock* B) { return B->pred_end(); }
|
||||
|
||||
static StmtItr StmtBegin(const CFGBlock* B) { return B->rbegin(); }
|
||||
static StmtItr StmtEnd(const CFGBlock* B) { return B->rend(); }
|
||||
|
||||
static BlockEdge PrevEdge(const CFGBlock* B, const CFGBlock* Prev) {
|
||||
return BlockEdge(B, Prev);
|
||||
}
|
||||
|
||||
static BlockEdge NextEdge(const CFGBlock* B, const CFGBlock* Next) {
|
||||
return BlockEdge(Next, B);
|
||||
}
|
||||
};
|
||||
} // end namespace dataflow
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// DataflowSolverTy - Generic dataflow solver.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
template <typename _DFValuesTy, // Usually a subclass of DataflowValues
|
||||
typename _TransferFuncsTy,
|
||||
typename _MergeOperatorTy,
|
||||
typename _Equal = std::equal_to<typename _DFValuesTy::ValTy> >
|
||||
class DataflowSolver {
|
||||
|
||||
//===----------------------------------------------------===//
|
||||
// Type declarations.
|
||||
//===----------------------------------------------------===//
|
||||
|
||||
public:
|
||||
typedef _DFValuesTy DFValuesTy;
|
||||
typedef _TransferFuncsTy TransferFuncsTy;
|
||||
typedef _MergeOperatorTy MergeOperatorTy;
|
||||
|
||||
typedef typename _DFValuesTy::AnalysisDirTag AnalysisDirTag;
|
||||
typedef typename _DFValuesTy::ValTy ValTy;
|
||||
typedef typename _DFValuesTy::EdgeDataMapTy EdgeDataMapTy;
|
||||
typedef typename _DFValuesTy::BlockDataMapTy BlockDataMapTy;
|
||||
|
||||
typedef dataflow::ItrTraits<AnalysisDirTag> ItrTraits;
|
||||
typedef typename ItrTraits::NextBItr NextBItr;
|
||||
typedef typename ItrTraits::PrevBItr PrevBItr;
|
||||
typedef typename ItrTraits::StmtItr StmtItr;
|
||||
|
||||
//===----------------------------------------------------===//
|
||||
// External interface: constructing and running the solver.
|
||||
//===----------------------------------------------------===//
|
||||
|
||||
public:
|
||||
DataflowSolver(DFValuesTy& d) : D(d), TF(d.getAnalysisData()) {}
|
||||
~DataflowSolver() {}
|
||||
|
||||
/// runOnCFG - Computes dataflow values for all blocks in a CFG.
|
||||
void runOnCFG(CFG& cfg, bool recordStmtValues = false) {
|
||||
// Set initial dataflow values and boundary conditions.
|
||||
D.InitializeValues(cfg);
|
||||
// Solve the dataflow equations. This will populate D.EdgeDataMap
|
||||
// with dataflow values.
|
||||
SolveDataflowEquations(cfg, recordStmtValues);
|
||||
}
|
||||
|
||||
/// runOnBlock - Computes dataflow values for a given block. This
|
||||
/// should usually be invoked only after previously computing
|
||||
/// dataflow values using runOnCFG, as runOnBlock is intended to
|
||||
/// only be used for querying the dataflow values within a block
|
||||
/// with and Observer object.
|
||||
void runOnBlock(const CFGBlock* B, bool recordStmtValues) {
|
||||
BlockDataMapTy& M = D.getBlockDataMap();
|
||||
typename BlockDataMapTy::iterator I = M.find(B);
|
||||
|
||||
if (I != M.end()) {
|
||||
TF.getVal().copyValues(I->second);
|
||||
ProcessBlock(B, recordStmtValues, AnalysisDirTag());
|
||||
}
|
||||
}
|
||||
|
||||
void runOnBlock(const CFGBlock& B, bool recordStmtValues) {
|
||||
runOnBlock(&B, recordStmtValues);
|
||||
}
|
||||
void runOnBlock(CFG::iterator& I, bool recordStmtValues) {
|
||||
runOnBlock(*I, recordStmtValues);
|
||||
}
|
||||
void runOnBlock(CFG::const_iterator& I, bool recordStmtValues) {
|
||||
runOnBlock(*I, recordStmtValues);
|
||||
}
|
||||
|
||||
void runOnAllBlocks(const CFG& cfg, bool recordStmtValues = false) {
|
||||
for (CFG::const_iterator I=cfg.begin(), E=cfg.end(); I!=E; ++I)
|
||||
runOnBlock(I, recordStmtValues);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------===//
|
||||
// Internal solver logic.
|
||||
//===----------------------------------------------------===//
|
||||
|
||||
private:
|
||||
|
||||
/// SolveDataflowEquations - Perform the actual worklist algorithm
|
||||
/// to compute dataflow values.
|
||||
void SolveDataflowEquations(CFG& cfg, bool recordStmtValues) {
|
||||
// Enqueue all blocks to ensure the dataflow values are computed
|
||||
// for every block. Not all blocks are guaranteed to reach the exit block.
|
||||
for (CFG::iterator I=cfg.begin(), E=cfg.end(); I!=E; ++I)
|
||||
WorkList.enqueue(&*I);
|
||||
|
||||
while (!WorkList.isEmpty()) {
|
||||
const CFGBlock* B = WorkList.dequeue();
|
||||
ProcessMerge(cfg,B);
|
||||
ProcessBlock(B, recordStmtValues, AnalysisDirTag());
|
||||
UpdateEdges(cfg,B,TF.getVal());
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessMerge(CFG& cfg, const CFGBlock* B) {
|
||||
ValTy& V = TF.getVal();
|
||||
TF.SetTopValue(V);
|
||||
|
||||
// Merge dataflow values from all predecessors of this block.
|
||||
MergeOperatorTy Merge;
|
||||
|
||||
EdgeDataMapTy& M = D.getEdgeDataMap();
|
||||
bool firstMerge = true;
|
||||
|
||||
for (PrevBItr I=ItrTraits::PrevBegin(B),E=ItrTraits::PrevEnd(B); I!=E; ++I){
|
||||
|
||||
typename EdgeDataMapTy::iterator EI =
|
||||
M.find(ItrTraits::PrevEdge(B, *I));
|
||||
|
||||
if (EI != M.end()) {
|
||||
if (firstMerge) {
|
||||
firstMerge = false;
|
||||
V.copyValues(EI->second);
|
||||
}
|
||||
else Merge(V,EI->second);
|
||||
}
|
||||
}
|
||||
|
||||
// Set the data for the block.
|
||||
D.getBlockDataMap()[B].copyValues(V);
|
||||
}
|
||||
|
||||
/// ProcessBlock - Process the transfer functions for a given block.
|
||||
void ProcessBlock(const CFGBlock* B, bool recordStmtValues,
|
||||
dataflow::forward_analysis_tag) {
|
||||
|
||||
for (StmtItr I=ItrTraits::StmtBegin(B), E=ItrTraits::StmtEnd(B); I!=E;++I)
|
||||
ProcessStmt(*I, recordStmtValues, AnalysisDirTag());
|
||||
|
||||
TF.VisitTerminator(const_cast<CFGBlock*>(B));
|
||||
}
|
||||
|
||||
void ProcessBlock(const CFGBlock* B, bool recordStmtValues,
|
||||
dataflow::backward_analysis_tag) {
|
||||
|
||||
TF.VisitTerminator(const_cast<CFGBlock*>(B));
|
||||
|
||||
for (StmtItr I=ItrTraits::StmtBegin(B), E=ItrTraits::StmtEnd(B); I!=E;++I)
|
||||
ProcessStmt(*I, recordStmtValues, AnalysisDirTag());
|
||||
}
|
||||
|
||||
void ProcessStmt(const Stmt* S, bool record, dataflow::forward_analysis_tag) {
|
||||
if (record) D.getStmtDataMap()[S] = TF.getVal();
|
||||
TF.BlockStmt_Visit(const_cast<Stmt*>(S));
|
||||
}
|
||||
|
||||
void ProcessStmt(const Stmt* S, bool record, dataflow::backward_analysis_tag){
|
||||
TF.BlockStmt_Visit(const_cast<Stmt*>(S));
|
||||
if (record) D.getStmtDataMap()[S] = TF.getVal();
|
||||
}
|
||||
|
||||
/// UpdateEdges - After processing the transfer functions for a
|
||||
/// block, update the dataflow value associated with the block's
|
||||
/// outgoing/incoming edges (depending on whether we do a
|
||||
// forward/backward analysis respectively)
|
||||
void UpdateEdges(CFG& cfg, const CFGBlock* B, ValTy& V) {
|
||||
for (NextBItr I=ItrTraits::NextBegin(B), E=ItrTraits::NextEnd(B); I!=E; ++I)
|
||||
UpdateEdgeValue(ItrTraits::NextEdge(B, *I),V,*I);
|
||||
}
|
||||
|
||||
/// UpdateEdgeValue - Update the value associated with a given edge.
|
||||
void UpdateEdgeValue(BlockEdge E, ValTy& V, const CFGBlock* TargetBlock) {
|
||||
EdgeDataMapTy& M = D.getEdgeDataMap();
|
||||
typename EdgeDataMapTy::iterator I = M.find(E);
|
||||
|
||||
if (I == M.end()) { // First computed value for this edge?
|
||||
M[E].copyValues(V);
|
||||
WorkList.enqueue(TargetBlock);
|
||||
}
|
||||
else if (!_Equal()(V,I->second)) {
|
||||
I->second.copyValues(V);
|
||||
WorkList.enqueue(TargetBlock);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
DFValuesTy& D;
|
||||
DataflowWorkListTy WorkList;
|
||||
TransferFuncsTy TF;
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
#endif
|
||||
@@ -1,172 +0,0 @@
|
||||
//===--- DataflowValues.h - Data structure for dataflow values --*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines a skeleton data structure for encapsulating the dataflow
|
||||
// values for a CFG. Typically this is subclassed to provide methods for
|
||||
// computing these values from a CFG.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSES_DATAFLOW_VALUES
|
||||
#define LLVM_CLANG_ANALYSES_DATAFLOW_VALUES
|
||||
|
||||
#include "clang/AST/CFG.h"
|
||||
#include "clang/Analysis/ProgramPoint.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// Dataflow Directional Tag Classes. These are used for tag dispatching
|
||||
/// within the dataflow solver/transfer functions to determine what direction
|
||||
/// a dataflow analysis flows.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace clang {
|
||||
namespace dataflow {
|
||||
struct forward_analysis_tag {};
|
||||
struct backward_analysis_tag {};
|
||||
} // end namespace dataflow
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// DataflowValues. Container class to store dataflow values for a CFG.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
template <typename ValueTypes,
|
||||
typename _AnalysisDirTag = dataflow::forward_analysis_tag >
|
||||
class DataflowValues {
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Type declarations.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
public:
|
||||
typedef typename ValueTypes::ValTy ValTy;
|
||||
typedef typename ValueTypes::AnalysisDataTy AnalysisDataTy;
|
||||
typedef _AnalysisDirTag AnalysisDirTag;
|
||||
typedef llvm::DenseMap<ProgramPoint, ValTy> EdgeDataMapTy;
|
||||
typedef llvm::DenseMap<const CFGBlock*, ValTy> BlockDataMapTy;
|
||||
typedef llvm::DenseMap<const Stmt*, ValTy> StmtDataMapTy;
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Predicates.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
public:
|
||||
/// isForwardAnalysis - Returns true if the dataflow values are computed
|
||||
/// from a forward analysis.
|
||||
bool isForwardAnalysis() { return isForwardAnalysis(AnalysisDirTag()); }
|
||||
|
||||
/// isBackwardAnalysis - Returns true if the dataflow values are computed
|
||||
/// from a backward analysis.
|
||||
bool isBackwardAnalysis() { return !isForwardAnalysis(); }
|
||||
|
||||
private:
|
||||
bool isForwardAnalysis(dataflow::forward_analysis_tag) { return true; }
|
||||
bool isForwardAnalysis(dataflow::backward_analysis_tag) { return false; }
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Initialization and accessors methods.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
public:
|
||||
DataflowValues() : StmtDataMap(NULL) {}
|
||||
~DataflowValues() { delete StmtDataMap; }
|
||||
|
||||
/// InitializeValues - Invoked by the solver to initialize state needed for
|
||||
/// dataflow analysis. This method is usually specialized by subclasses.
|
||||
void InitializeValues(const CFG& cfg) {};
|
||||
|
||||
|
||||
/// getEdgeData - Retrieves the dataflow values associated with a
|
||||
/// CFG edge.
|
||||
ValTy& getEdgeData(const BlockEdge& E) {
|
||||
typename EdgeDataMapTy::iterator I = EdgeDataMap.find(E);
|
||||
assert (I != EdgeDataMap.end() && "No data associated with Edge.");
|
||||
return I->second;
|
||||
}
|
||||
|
||||
const ValTy& getEdgeData(const BlockEdge& E) const {
|
||||
return reinterpret_cast<DataflowValues*>(this)->getEdgeData(E);
|
||||
}
|
||||
|
||||
/// getBlockData - Retrieves the dataflow values associated with a
|
||||
/// specified CFGBlock. If the dataflow analysis is a forward analysis,
|
||||
/// this data is associated with the END of the block. If the analysis
|
||||
/// is a backwards analysis, it is associated with the ENTRY of the block.
|
||||
ValTy& getBlockData(const CFGBlock* B) {
|
||||
typename BlockDataMapTy::iterator I = BlockDataMap.find(B);
|
||||
assert (I != BlockDataMap.end() && "No data associated with block.");
|
||||
return I->second;
|
||||
}
|
||||
|
||||
const ValTy& getBlockData(const CFGBlock* B) const {
|
||||
return const_cast<DataflowValues*>(this)->getBlockData(B);
|
||||
}
|
||||
|
||||
/// getStmtData - Retrieves the dataflow values associated with a
|
||||
/// specified Stmt. If the dataflow analysis is a forward analysis,
|
||||
/// this data corresponds to the point immediately before a Stmt.
|
||||
/// If the analysis is a backwards analysis, it is associated with
|
||||
/// the point after a Stmt. This data is only computed for block-level
|
||||
/// expressions, and only when requested when the analysis is executed.
|
||||
ValTy& getStmtData(const Stmt* S) {
|
||||
assert (StmtDataMap && "Dataflow values were not computed for statements.");
|
||||
typename StmtDataMapTy::iterator I = StmtDataMap->find(S);
|
||||
assert (I != StmtDataMap->end() && "No data associated with statement.");
|
||||
return I->second;
|
||||
}
|
||||
|
||||
const ValTy& getStmtData(const Stmt* S) const {
|
||||
return const_cast<DataflowValues*>(this)->getStmtData(S);
|
||||
}
|
||||
|
||||
/// getEdgeDataMap - Retrieves the internal map between CFG edges and
|
||||
/// dataflow values. Usually used by a dataflow solver to compute
|
||||
/// values for blocks.
|
||||
EdgeDataMapTy& getEdgeDataMap() { return EdgeDataMap; }
|
||||
const EdgeDataMapTy& getEdgeDataMap() const { return EdgeDataMap; }
|
||||
|
||||
/// getBlockDataMap - Retrieves the internal map between CFGBlocks and
|
||||
/// dataflow values. If the dataflow analysis operates in the forward
|
||||
/// direction, the values correspond to the dataflow values at the start
|
||||
/// of the block. Otherwise, for a backward analysis, the values correpsond
|
||||
/// to the dataflow values at the end of the block.
|
||||
BlockDataMapTy& getBlockDataMap() { return BlockDataMap; }
|
||||
const BlockDataMapTy& getBlockDataMap() const { return BlockDataMap; }
|
||||
|
||||
/// getStmtDataMap - Retrieves the internal map between Stmts and
|
||||
/// dataflow values.
|
||||
StmtDataMapTy& getStmtDataMap() {
|
||||
if (!StmtDataMap) StmtDataMap = new StmtDataMapTy();
|
||||
return *StmtDataMap;
|
||||
}
|
||||
|
||||
const StmtDataMapTy& getStmtDataMap() const {
|
||||
return const_cast<DataflowValues*>(this)->getStmtDataMap();
|
||||
}
|
||||
|
||||
/// getAnalysisData - Retrieves the meta data associated with a
|
||||
/// dataflow analysis for analyzing a particular CFG.
|
||||
/// This is typically consumed by transfer function code (via the solver).
|
||||
/// This can also be used by subclasses to interpret the dataflow values.
|
||||
AnalysisDataTy& getAnalysisData() { return AnalysisData; }
|
||||
const AnalysisDataTy& getAnalysisData() const { return AnalysisData; }
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Internal data.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
protected:
|
||||
EdgeDataMapTy EdgeDataMap;
|
||||
BlockDataMapTy BlockDataMap;
|
||||
StmtDataMapTy* StmtDataMap;
|
||||
AnalysisDataTy AnalysisData;
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
#endif
|
||||
@@ -1,54 +0,0 @@
|
||||
//==- LocalCheckers.h - Intra-Procedural+Flow-Sensitive Checkers -*- C++ -*-==//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the interface to call a set of intra-procedural (local)
|
||||
// checkers that use flow/path-sensitive analyses to find bugs.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSIS_LOCALCHECKERS_H
|
||||
#define LLVM_CLANG_ANALYSIS_LOCALCHECKERS_H
|
||||
|
||||
namespace clang {
|
||||
|
||||
class CFG;
|
||||
class Decl;
|
||||
class Diagnostic;
|
||||
class ASTContext;
|
||||
class PathDiagnosticClient;
|
||||
class GRTransferFuncs;
|
||||
class BugType;
|
||||
class LangOptions;
|
||||
class ParentMap;
|
||||
class LiveVariables;
|
||||
class BugReporter;
|
||||
class ObjCImplementationDecl;
|
||||
class LangOptions;
|
||||
class GRExprEngine;
|
||||
|
||||
void CheckDeadStores(LiveVariables& L, BugReporter& BR);
|
||||
|
||||
void CheckUninitializedValues(CFG& cfg, ASTContext& Ctx, Diagnostic& Diags,
|
||||
bool FullUninitTaint=false);
|
||||
|
||||
GRTransferFuncs* MakeGRSimpleValsTF();
|
||||
GRTransferFuncs* MakeCFRefCountTF(ASTContext& Ctx, bool GCEnabled,
|
||||
const LangOptions& lopts);
|
||||
|
||||
void CheckObjCDealloc(ObjCImplementationDecl* D, const LangOptions& L,
|
||||
BugReporter& BR);
|
||||
|
||||
void CheckObjCInstMethSignature(ObjCImplementationDecl* ID, BugReporter& BR);
|
||||
void CheckObjCUnusedIvar(ObjCImplementationDecl* D, BugReporter& BR);
|
||||
|
||||
void RegisterAppleChecks(GRExprEngine& Eng);
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
@@ -1,210 +0,0 @@
|
||||
//===--- PathDiagnostic.h - Path-Specific Diagnostic Handling ---*- 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 PathDiagnostic-related interfaces.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_PATH_DIAGNOSTIC_H
|
||||
#define LLVM_CLANG_PATH_DIAGNOSTIC_H
|
||||
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
|
||||
namespace clang {
|
||||
|
||||
class PathDiagnosticPiece {
|
||||
public:
|
||||
enum DisplayHint { Above, Below };
|
||||
|
||||
private:
|
||||
FullSourceLoc Pos;
|
||||
std::string str;
|
||||
DisplayHint Hint;
|
||||
std::vector<SourceRange> ranges;
|
||||
|
||||
public:
|
||||
|
||||
PathDiagnosticPiece(FullSourceLoc pos, const std::string& s,
|
||||
DisplayHint hint = Above)
|
||||
: Pos(pos), str(s), Hint(hint) {}
|
||||
|
||||
PathDiagnosticPiece(FullSourceLoc pos, const char* s,
|
||||
DisplayHint hint = Above)
|
||||
: Pos(pos), str(s), Hint(hint) {}
|
||||
|
||||
const std::string& getString() const { return str; }
|
||||
|
||||
DisplayHint getDisplayHint() const { return Hint; }
|
||||
|
||||
void addRange(SourceRange R) {
|
||||
ranges.push_back(R);
|
||||
}
|
||||
|
||||
void addRange(SourceLocation B, SourceLocation E) {
|
||||
ranges.push_back(SourceRange(B,E));
|
||||
}
|
||||
|
||||
typedef const SourceRange* range_iterator;
|
||||
|
||||
range_iterator ranges_begin() const {
|
||||
return ranges.empty() ? NULL : &ranges[0];
|
||||
}
|
||||
|
||||
range_iterator ranges_end() const {
|
||||
return ranges_begin() + ranges.size();
|
||||
}
|
||||
|
||||
const SourceManager& getSourceManager() const {
|
||||
return Pos.getManager();
|
||||
}
|
||||
|
||||
FullSourceLoc getLocation() const { return Pos; }
|
||||
};
|
||||
|
||||
class PathDiagnostic {
|
||||
std::list<PathDiagnosticPiece*> path;
|
||||
unsigned Size;
|
||||
std::string Desc;
|
||||
std::string Category;
|
||||
std::string BugType;
|
||||
std::vector<std::string> OtherDesc;
|
||||
|
||||
public:
|
||||
PathDiagnostic() : Size(0) {}
|
||||
|
||||
PathDiagnostic(const char* bugtype, const char* desc, const char* category)
|
||||
: Size(0), Desc(desc), Category(category), BugType(bugtype) {}
|
||||
|
||||
PathDiagnostic(const std::string& bugtype, const std::string& desc,
|
||||
const std::string& category)
|
||||
: Size(0), Desc(desc), Category(category), BugType(bugtype) {}
|
||||
|
||||
~PathDiagnostic();
|
||||
|
||||
const std::string& getDescription() const { return Desc; }
|
||||
const std::string& getBugType() const { return BugType; }
|
||||
const std::string& getCategory() const { return Category; }
|
||||
|
||||
typedef std::vector<std::string>::const_iterator meta_iterator;
|
||||
meta_iterator meta_begin() const { return OtherDesc.begin(); }
|
||||
meta_iterator meta_end() const { return OtherDesc.end(); }
|
||||
void addMeta(const std::string& s) { OtherDesc.push_back(s); }
|
||||
void addMeta(const char* s) { OtherDesc.push_back(s); }
|
||||
|
||||
void push_front(PathDiagnosticPiece* piece) {
|
||||
path.push_front(piece);
|
||||
++Size;
|
||||
}
|
||||
|
||||
void push_back(PathDiagnosticPiece* piece) {
|
||||
path.push_back(piece);
|
||||
++Size;
|
||||
}
|
||||
|
||||
PathDiagnosticPiece* back() {
|
||||
return path.back();
|
||||
}
|
||||
|
||||
const PathDiagnosticPiece* back() const {
|
||||
return path.back();
|
||||
}
|
||||
|
||||
unsigned size() const { return Size; }
|
||||
bool empty() const { return Size == 0; }
|
||||
|
||||
class iterator {
|
||||
public:
|
||||
typedef std::list<PathDiagnosticPiece*>::iterator ImplTy;
|
||||
|
||||
typedef PathDiagnosticPiece value_type;
|
||||
typedef value_type& reference;
|
||||
typedef value_type* pointer;
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef std::bidirectional_iterator_tag iterator_category;
|
||||
|
||||
private:
|
||||
ImplTy I;
|
||||
|
||||
public:
|
||||
iterator(const ImplTy& i) : I(i) {}
|
||||
|
||||
bool operator==(const iterator& X) const { return I == X.I; }
|
||||
bool operator!=(const iterator& X) const { return I != X.I; }
|
||||
|
||||
PathDiagnosticPiece& operator*() const { return **I; }
|
||||
PathDiagnosticPiece* operator->() const { return *I; }
|
||||
|
||||
iterator& operator++() { ++I; return *this; }
|
||||
iterator& operator--() { --I; return *this; }
|
||||
};
|
||||
|
||||
class const_iterator {
|
||||
public:
|
||||
typedef std::list<PathDiagnosticPiece*>::const_iterator ImplTy;
|
||||
|
||||
typedef const PathDiagnosticPiece value_type;
|
||||
typedef value_type& reference;
|
||||
typedef value_type* pointer;
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef std::bidirectional_iterator_tag iterator_category;
|
||||
|
||||
private:
|
||||
ImplTy I;
|
||||
|
||||
public:
|
||||
const_iterator(const ImplTy& i) : I(i) {}
|
||||
|
||||
bool operator==(const const_iterator& X) const { return I == X.I; }
|
||||
bool operator!=(const const_iterator& X) const { return I != X.I; }
|
||||
|
||||
reference operator*() const { return **I; }
|
||||
pointer operator->() const { return *I; }
|
||||
|
||||
const_iterator& operator++() { ++I; return *this; }
|
||||
const_iterator& operator--() { --I; return *this; }
|
||||
};
|
||||
|
||||
typedef std::reverse_iterator<iterator> reverse_iterator;
|
||||
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
|
||||
|
||||
|
||||
// forward iterator creation methods.
|
||||
|
||||
iterator begin() { return path.begin(); }
|
||||
iterator end() { return path.end(); }
|
||||
|
||||
const_iterator begin() const { return path.begin(); }
|
||||
const_iterator end() const { return path.end(); }
|
||||
|
||||
// reverse iterator creation methods.
|
||||
reverse_iterator rbegin() { return reverse_iterator(end()); }
|
||||
const_reverse_iterator rbegin() const{ return const_reverse_iterator(end()); }
|
||||
reverse_iterator rend() { return reverse_iterator(begin()); }
|
||||
const_reverse_iterator rend() const { return const_reverse_iterator(begin());}
|
||||
};
|
||||
|
||||
class PathDiagnosticClient : public DiagnosticClient {
|
||||
public:
|
||||
PathDiagnosticClient() {}
|
||||
virtual ~PathDiagnosticClient() {}
|
||||
|
||||
virtual void HandleDiagnostic(Diagnostic::Level DiagLevel,
|
||||
const DiagnosticInfo &Info);
|
||||
|
||||
virtual void HandlePathDiagnostic(const PathDiagnostic* D) = 0;
|
||||
};
|
||||
|
||||
} //end clang namespace
|
||||
#endif
|
||||
@@ -1,121 +0,0 @@
|
||||
//=== BasicValueFactory.h - Basic values for Path Sens analysis --*- C++ -*---//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines BasicValueFactory, a class that manages the lifetime
|
||||
// of APSInt objects and symbolic constraints used by GRExprEngine
|
||||
// and related classes.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSIS_BASICVALUEFACTORY_H
|
||||
#define LLVM_CLANG_ANALYSIS_BASICVALUEFACTORY_H
|
||||
|
||||
#include "clang/Analysis/PathSensitive/SymbolManager.h"
|
||||
#include "clang/Analysis/PathSensitive/SVals.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
#include "llvm/ADT/APSInt.h"
|
||||
#include "llvm/ADT/ImmutableList.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
class CompoundValData : public llvm::FoldingSetNode {
|
||||
QualType T;
|
||||
llvm::ImmutableList<SVal> L;
|
||||
|
||||
public:
|
||||
CompoundValData(QualType t, llvm::ImmutableList<SVal> l)
|
||||
: T(t), L(l) {}
|
||||
|
||||
typedef llvm::ImmutableList<SVal>::iterator iterator;
|
||||
iterator begin() const { return L.begin(); }
|
||||
iterator end() const { return L.end(); }
|
||||
|
||||
static void Profile(llvm::FoldingSetNodeID& ID, QualType T,
|
||||
llvm::ImmutableList<SVal> L);
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID& ID) { Profile(ID, T, L); }
|
||||
};
|
||||
|
||||
class BasicValueFactory {
|
||||
typedef llvm::FoldingSet<llvm::FoldingSetNodeWrapper<llvm::APSInt> >
|
||||
APSIntSetTy;
|
||||
|
||||
typedef llvm::FoldingSet<SymIntConstraint>
|
||||
SymIntCSetTy;
|
||||
|
||||
|
||||
ASTContext& Ctx;
|
||||
llvm::BumpPtrAllocator& BPAlloc;
|
||||
|
||||
APSIntSetTy APSIntSet;
|
||||
SymIntCSetTy SymIntCSet;
|
||||
void* PersistentSVals;
|
||||
void* PersistentSValPairs;
|
||||
|
||||
llvm::ImmutableList<SVal>::Factory SValListFactory;
|
||||
llvm::FoldingSet<CompoundValData> CompoundValDataSet;
|
||||
|
||||
public:
|
||||
BasicValueFactory(ASTContext& ctx, llvm::BumpPtrAllocator& Alloc)
|
||||
: Ctx(ctx), BPAlloc(Alloc), PersistentSVals(0), PersistentSValPairs(0),
|
||||
SValListFactory(Alloc) {}
|
||||
|
||||
~BasicValueFactory();
|
||||
|
||||
ASTContext& getContext() const { return Ctx; }
|
||||
|
||||
const llvm::APSInt& getValue(const llvm::APSInt& X);
|
||||
const llvm::APSInt& getValue(const llvm::APInt& X, bool isUnsigned);
|
||||
const llvm::APSInt& getValue(uint64_t X, unsigned BitWidth, bool isUnsigned);
|
||||
const llvm::APSInt& getValue(uint64_t X, QualType T);
|
||||
|
||||
const llvm::APSInt& getIntValue(uint64_t X, bool isUnsigned) {
|
||||
QualType T = isUnsigned ? Ctx.UnsignedIntTy : Ctx.IntTy;
|
||||
return getValue(X, T);
|
||||
}
|
||||
|
||||
inline const llvm::APSInt& getZeroWithPtrWidth(bool isUnsigned = true) {
|
||||
return getValue(0, Ctx.getTypeSize(Ctx.VoidPtrTy), isUnsigned);
|
||||
}
|
||||
|
||||
inline const llvm::APSInt& getTruthValue(bool b) {
|
||||
return getValue(b ? 1 : 0, Ctx.getTypeSize(Ctx.IntTy), false);
|
||||
}
|
||||
|
||||
const SymIntConstraint& getConstraint(SymbolRef sym, BinaryOperator::Opcode Op,
|
||||
const llvm::APSInt& V);
|
||||
|
||||
const CompoundValData* getCompoundValData(QualType T,
|
||||
llvm::ImmutableList<SVal> Vals);
|
||||
|
||||
llvm::ImmutableList<SVal> getEmptySValList() {
|
||||
return SValListFactory.GetEmptyList();
|
||||
}
|
||||
|
||||
llvm::ImmutableList<SVal> consVals(SVal X, llvm::ImmutableList<SVal> L) {
|
||||
return SValListFactory.Add(X, L);
|
||||
}
|
||||
|
||||
const llvm::APSInt* EvaluateAPSInt(BinaryOperator::Opcode Op,
|
||||
const llvm::APSInt& V1,
|
||||
const llvm::APSInt& V2);
|
||||
|
||||
const std::pair<SVal, uintptr_t>&
|
||||
getPersistentSValWithData(const SVal& V, uintptr_t Data);
|
||||
|
||||
const std::pair<SVal, SVal>&
|
||||
getPersistentSValPair(const SVal& V1, const SVal& V2);
|
||||
|
||||
const SVal* getPersistentSVal(SVal X);
|
||||
};
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
#endif
|
||||
@@ -1,335 +0,0 @@
|
||||
//===--- BugReporter.h - Generate PathDiagnostics --------------*- 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 BugReporter, a utility class for generating
|
||||
// PathDiagnostics for analyses based on GRState.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSIS_BUGREPORTER
|
||||
#define LLVM_CLANG_ANALYSIS_BUGREPORTER
|
||||
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "clang/Analysis/PathSensitive/GRState.h"
|
||||
#include "clang/Analysis/PathSensitive/ExplodedGraph.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/ADT/SmallSet.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
#include <list>
|
||||
|
||||
namespace clang {
|
||||
|
||||
class PathDiagnostic;
|
||||
class PathDiagnosticPiece;
|
||||
class PathDiagnosticClient;
|
||||
class ASTContext;
|
||||
class Diagnostic;
|
||||
class BugReporter;
|
||||
class GRExprEngine;
|
||||
class GRState;
|
||||
class Stmt;
|
||||
class BugReport;
|
||||
class ParentMap;
|
||||
|
||||
class BugType {
|
||||
public:
|
||||
BugType() {}
|
||||
virtual ~BugType();
|
||||
|
||||
virtual const char* getName() const = 0;
|
||||
virtual const char* getDescription() const { return getName(); }
|
||||
virtual const char* getCategory() const { return ""; }
|
||||
|
||||
virtual std::pair<const char**,const char**> getExtraDescriptiveText() {
|
||||
return std::pair<const char**, const char**>(0, 0);
|
||||
}
|
||||
|
||||
virtual void EmitWarnings(BugReporter& BR) {}
|
||||
virtual void GetErrorNodes(std::vector<ExplodedNode<GRState>*>& Nodes) {}
|
||||
|
||||
virtual bool isCached(BugReport& R) = 0;
|
||||
};
|
||||
|
||||
class BugTypeCacheLocation : public BugType {
|
||||
llvm::SmallSet<ProgramPoint,10> CachedErrors;
|
||||
public:
|
||||
BugTypeCacheLocation() {}
|
||||
virtual ~BugTypeCacheLocation() {}
|
||||
virtual bool isCached(BugReport& R);
|
||||
bool isCached(ProgramPoint P);
|
||||
};
|
||||
|
||||
|
||||
class BugReport {
|
||||
BugType& Desc;
|
||||
const ExplodedNode<GRState> *EndNode;
|
||||
SourceRange R;
|
||||
public:
|
||||
BugReport(BugType& D, const ExplodedNode<GRState> *n) : Desc(D), EndNode(n) {}
|
||||
virtual ~BugReport();
|
||||
|
||||
const BugType& getBugType() const { return Desc; }
|
||||
BugType& getBugType() { return Desc; }
|
||||
|
||||
const ExplodedNode<GRState>* getEndNode() const { return EndNode; }
|
||||
|
||||
Stmt* getStmt(BugReporter& BR) const;
|
||||
|
||||
const char* getName() const { return getBugType().getName(); }
|
||||
|
||||
virtual const char* getDescription() const {
|
||||
return getBugType().getDescription();
|
||||
}
|
||||
|
||||
virtual const char* getCategory() const {
|
||||
return getBugType().getCategory();
|
||||
}
|
||||
|
||||
virtual std::pair<const char**,const char**> getExtraDescriptiveText() {
|
||||
return getBugType().getExtraDescriptiveText();
|
||||
}
|
||||
|
||||
virtual PathDiagnosticPiece* getEndPath(BugReporter& BR,
|
||||
const ExplodedNode<GRState>* N);
|
||||
|
||||
virtual FullSourceLoc getLocation(SourceManager& Mgr);
|
||||
|
||||
virtual void getRanges(BugReporter& BR,const SourceRange*& beg,
|
||||
const SourceRange*& end);
|
||||
|
||||
virtual PathDiagnosticPiece* VisitNode(const ExplodedNode<GRState>* N,
|
||||
const ExplodedNode<GRState>* PrevN,
|
||||
const ExplodedGraph<GRState>& G,
|
||||
BugReporter& BR);
|
||||
};
|
||||
|
||||
class RangedBugReport : public BugReport {
|
||||
std::vector<SourceRange> Ranges;
|
||||
const char* desc;
|
||||
public:
|
||||
RangedBugReport(BugType& D, ExplodedNode<GRState> *n,
|
||||
const char* description = 0)
|
||||
: BugReport(D, n), desc(description) {}
|
||||
|
||||
virtual ~RangedBugReport();
|
||||
|
||||
virtual const char* getDescription() const {
|
||||
return desc ? desc : BugReport::getDescription();
|
||||
}
|
||||
|
||||
void addRange(SourceRange R) { Ranges.push_back(R); }
|
||||
|
||||
|
||||
virtual void getRanges(BugReporter& BR,const SourceRange*& beg,
|
||||
const SourceRange*& end) {
|
||||
|
||||
if (Ranges.empty()) {
|
||||
beg = NULL;
|
||||
end = NULL;
|
||||
}
|
||||
else {
|
||||
beg = &Ranges[0];
|
||||
end = beg + Ranges.size();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class BugReporterData {
|
||||
public:
|
||||
virtual ~BugReporterData();
|
||||
virtual Diagnostic& getDiagnostic() = 0;
|
||||
virtual PathDiagnosticClient* getPathDiagnosticClient() = 0;
|
||||
virtual ASTContext& getContext() = 0;
|
||||
virtual SourceManager& getSourceManager() = 0;
|
||||
virtual CFG* getCFG() = 0;
|
||||
virtual ParentMap& getParentMap() = 0;
|
||||
virtual LiveVariables* getLiveVariables() = 0;
|
||||
};
|
||||
|
||||
class BugReporter {
|
||||
public:
|
||||
enum Kind { BaseBRKind, GRBugReporterKind };
|
||||
|
||||
protected:
|
||||
Kind kind;
|
||||
BugReporterData& D;
|
||||
|
||||
BugReporter(BugReporterData& d, Kind k) : kind(k), D(d) {}
|
||||
|
||||
public:
|
||||
BugReporter(BugReporterData& d) : kind(BaseBRKind), D(d) {}
|
||||
virtual ~BugReporter();
|
||||
|
||||
Kind getKind() const { return kind; }
|
||||
|
||||
Diagnostic& getDiagnostic() {
|
||||
return D.getDiagnostic();
|
||||
}
|
||||
|
||||
PathDiagnosticClient* getPathDiagnosticClient() {
|
||||
return D.getPathDiagnosticClient();
|
||||
}
|
||||
|
||||
ASTContext& getContext() {
|
||||
return D.getContext();
|
||||
}
|
||||
|
||||
SourceManager& getSourceManager() {
|
||||
return D.getSourceManager();
|
||||
}
|
||||
|
||||
CFG* getCFG() {
|
||||
return D.getCFG();
|
||||
}
|
||||
|
||||
ParentMap& getParentMap() {
|
||||
return D.getParentMap();
|
||||
}
|
||||
|
||||
LiveVariables* getLiveVariables() {
|
||||
return D.getLiveVariables();
|
||||
}
|
||||
|
||||
virtual void GeneratePathDiagnostic(PathDiagnostic& PD, BugReport& R) {}
|
||||
|
||||
void EmitWarning(BugReport& R);
|
||||
|
||||
void EmitBasicReport(const char* BugName, const char* BugStr,
|
||||
SourceLocation Loc,
|
||||
SourceRange* RangeBeg, unsigned NumRanges);
|
||||
|
||||
void EmitBasicReport(const char* BugName, const char* BugCategory,
|
||||
const char* BugStr, SourceLocation Loc,
|
||||
SourceRange* RangeBeg, unsigned NumRanges);
|
||||
|
||||
|
||||
void EmitBasicReport(const char* BugName, const char* BugStr,
|
||||
SourceLocation Loc) {
|
||||
EmitBasicReport(BugName, BugStr, Loc, 0, 0);
|
||||
}
|
||||
|
||||
void EmitBasicReport(const char* BugName, const char* BugCategory,
|
||||
const char* BugStr, SourceLocation Loc) {
|
||||
EmitBasicReport(BugName, BugCategory, BugStr, Loc, 0, 0);
|
||||
}
|
||||
|
||||
void EmitBasicReport(const char* BugName, const char* BugStr,
|
||||
SourceLocation Loc, SourceRange R) {
|
||||
EmitBasicReport(BugName, BugStr, Loc, &R, 1);
|
||||
}
|
||||
|
||||
void EmitBasicReport(const char* BugName, const char* Category,
|
||||
const char* BugStr, SourceLocation Loc, SourceRange R) {
|
||||
EmitBasicReport(BugName, Category, BugStr, Loc, &R, 1);
|
||||
}
|
||||
|
||||
static bool classof(const BugReporter* R) { return true; }
|
||||
};
|
||||
|
||||
class GRBugReporter : public BugReporter {
|
||||
GRExprEngine& Eng;
|
||||
llvm::SmallSet<SymbolRef, 10> NotableSymbols;
|
||||
public:
|
||||
|
||||
GRBugReporter(BugReporterData& d, GRExprEngine& eng)
|
||||
: BugReporter(d, GRBugReporterKind), Eng(eng) {}
|
||||
|
||||
virtual ~GRBugReporter();
|
||||
|
||||
/// getEngine - Return the analysis engine used to analyze a given
|
||||
/// function or method.
|
||||
GRExprEngine& getEngine() {
|
||||
return Eng;
|
||||
}
|
||||
|
||||
/// getGraph - Get the exploded graph created by the analysis engine
|
||||
/// for the analyzed method or function.
|
||||
ExplodedGraph<GRState>& getGraph();
|
||||
|
||||
/// getStateManager - Return the state manager used by the analysis
|
||||
/// engine.
|
||||
GRStateManager& getStateManager();
|
||||
|
||||
virtual void GeneratePathDiagnostic(PathDiagnostic& PD, BugReport& R);
|
||||
|
||||
void addNotableSymbol(SymbolRef Sym) {
|
||||
NotableSymbols.insert(Sym);
|
||||
}
|
||||
|
||||
bool isNotable(SymbolRef Sym) const {
|
||||
return (bool) NotableSymbols.count(Sym);
|
||||
}
|
||||
|
||||
/// classof - Used by isa<>, cast<>, and dyn_cast<>.
|
||||
static bool classof(const BugReporter* R) {
|
||||
return R->getKind() == GRBugReporterKind;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class DiagBugReport : public RangedBugReport {
|
||||
std::list<std::string> Strs;
|
||||
FullSourceLoc L;
|
||||
const char* description;
|
||||
public:
|
||||
DiagBugReport(const char* desc, BugType& D, FullSourceLoc l) :
|
||||
RangedBugReport(D, NULL), L(l), description(desc) {}
|
||||
|
||||
virtual ~DiagBugReport() {}
|
||||
virtual FullSourceLoc getLocation(SourceManager&) { return L; }
|
||||
|
||||
virtual const char* getDescription() const {
|
||||
return description;
|
||||
}
|
||||
|
||||
void addString(const std::string& s) { Strs.push_back(s); }
|
||||
|
||||
typedef std::list<std::string>::const_iterator str_iterator;
|
||||
str_iterator str_begin() const { return Strs.begin(); }
|
||||
str_iterator str_end() const { return Strs.end(); }
|
||||
};
|
||||
|
||||
class DiagCollector : public DiagnosticClient {
|
||||
std::list<DiagBugReport> Reports;
|
||||
BugType& D;
|
||||
public:
|
||||
DiagCollector(BugType& d) : D(d) {}
|
||||
|
||||
virtual ~DiagCollector() {}
|
||||
|
||||
bool IncludeInDiagnosticCounts() const { return false; }
|
||||
|
||||
void HandleDiagnostic(Diagnostic::Level DiagLevel,
|
||||
const DiagnosticInfo &Info);
|
||||
|
||||
// Iterators.
|
||||
typedef std::list<DiagBugReport>::iterator iterator;
|
||||
iterator begin() { return Reports.begin(); }
|
||||
iterator end() { return Reports.end(); }
|
||||
};
|
||||
|
||||
class SimpleBugType : public BugTypeCacheLocation {
|
||||
const char* name;
|
||||
const char* category;
|
||||
const char* desc;
|
||||
public:
|
||||
SimpleBugType(const char* n) : name(n), category(""), desc(0) {}
|
||||
SimpleBugType(const char* n, const char* c, const char* d)
|
||||
: name(n), category(c), desc(d) {}
|
||||
|
||||
virtual const char* getName() const { return name; }
|
||||
virtual const char* getDescription() const { return desc ? desc : name; }
|
||||
virtual const char* getCategory() const { return category; }
|
||||
};
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
#endif
|
||||
@@ -1,59 +0,0 @@
|
||||
//== ConstraintManager.h - Constraints on symbolic values.-------*- C++ -*--==//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defined the interface to manage constraints on symbolic values.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSIS_CONSTRAINT_MANAGER_H
|
||||
#define LLVM_CLANG_ANALYSIS_CONSTRAINT_MANAGER_H
|
||||
|
||||
// FIXME: Typedef LiveSymbolsTy/DeadSymbolsTy at a more appropriate place.
|
||||
#include "clang/Analysis/PathSensitive/Store.h"
|
||||
|
||||
namespace llvm {
|
||||
class APSInt;
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
|
||||
class GRState;
|
||||
class GRStateManager;
|
||||
class SVal;
|
||||
class SymbolRef;
|
||||
|
||||
class ConstraintManager {
|
||||
public:
|
||||
virtual ~ConstraintManager();
|
||||
virtual const GRState* Assume(const GRState* St, SVal Cond,
|
||||
bool Assumption, bool& isFeasible) = 0;
|
||||
|
||||
virtual const GRState* AssumeInBound(const GRState* St, SVal Idx,
|
||||
SVal UpperBound, bool Assumption,
|
||||
bool& isFeasible) = 0;
|
||||
|
||||
virtual const llvm::APSInt* getSymVal(const GRState* St, SymbolRef sym) = 0;
|
||||
|
||||
virtual bool isEqual(const GRState* St, SymbolRef sym,
|
||||
const llvm::APSInt& V) const = 0;
|
||||
|
||||
virtual const GRState* RemoveDeadBindings(const GRState* St,
|
||||
SymbolReaper& SymReaper) = 0;
|
||||
|
||||
virtual void print(const GRState* St, std::ostream& Out,
|
||||
const char* nl, const char *sep) = 0;
|
||||
|
||||
virtual void EndPath(const GRState* St) {}
|
||||
};
|
||||
|
||||
ConstraintManager* CreateBasicConstraintManager(GRStateManager& statemgr);
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
#endif
|
||||
@@ -1,150 +0,0 @@
|
||||
//== Environment.h - Map from Stmt* to Locations/Values ---------*- C++ -*--==//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defined the Environment and EnvironmentManager classes.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSIS_ENVIRONMENT_H
|
||||
#define LLVM_CLANG_ANALYSIS_ENVIRONMENT_H
|
||||
|
||||
// For using typedefs in StoreManager. Should find a better place for these
|
||||
// typedefs.
|
||||
#include "clang/Analysis/PathSensitive/Store.h"
|
||||
|
||||
#include "llvm/ADT/ImmutableMap.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "clang/Analysis/PathSensitive/SVals.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
class EnvironmentManager;
|
||||
class BasicValueFactory;
|
||||
class LiveVariables;
|
||||
|
||||
class Environment : public llvm::FoldingSetNode {
|
||||
private:
|
||||
|
||||
friend class EnvironmentManager;
|
||||
|
||||
// Type definitions.
|
||||
typedef llvm::ImmutableMap<Stmt*,SVal> BindingsTy;
|
||||
|
||||
// Data.
|
||||
BindingsTy SubExprBindings;
|
||||
BindingsTy BlkExprBindings;
|
||||
|
||||
Environment(BindingsTy seb, BindingsTy beb)
|
||||
: SubExprBindings(seb), BlkExprBindings(beb) {}
|
||||
|
||||
public:
|
||||
|
||||
typedef BindingsTy::iterator seb_iterator;
|
||||
seb_iterator seb_begin() const { return SubExprBindings.begin(); }
|
||||
seb_iterator seb_end() const { return SubExprBindings.end(); }
|
||||
|
||||
typedef BindingsTy::iterator beb_iterator;
|
||||
beb_iterator beb_begin() const { return BlkExprBindings.begin(); }
|
||||
beb_iterator beb_end() const { return BlkExprBindings.end(); }
|
||||
|
||||
SVal LookupSubExpr(Stmt* E) const {
|
||||
const SVal* X = SubExprBindings.lookup(cast<Expr>(E));
|
||||
return X ? *X : UnknownVal();
|
||||
}
|
||||
|
||||
SVal LookupBlkExpr(Stmt* E) const {
|
||||
const SVal* X = BlkExprBindings.lookup(E);
|
||||
return X ? *X : UnknownVal();
|
||||
}
|
||||
|
||||
SVal LookupExpr(Stmt* E) const {
|
||||
const SVal* X = SubExprBindings.lookup(E);
|
||||
if (X) return *X;
|
||||
X = BlkExprBindings.lookup(E);
|
||||
return X ? *X : UnknownVal();
|
||||
}
|
||||
|
||||
SVal GetSVal(Stmt* Ex, BasicValueFactory& BasicVals) const;
|
||||
SVal GetBlkExprSVal(Stmt* Ex, BasicValueFactory& BasicVals) const;
|
||||
|
||||
/// Profile - Profile the contents of an Environment object for use
|
||||
/// in a FoldingSet.
|
||||
static void Profile(llvm::FoldingSetNodeID& ID, const Environment* E) {
|
||||
E->SubExprBindings.Profile(ID);
|
||||
E->BlkExprBindings.Profile(ID);
|
||||
}
|
||||
|
||||
/// Profile - Used to profile the contents of this object for inclusion
|
||||
/// in a FoldingSet.
|
||||
void Profile(llvm::FoldingSetNodeID& ID) const {
|
||||
Profile(ID, this);
|
||||
}
|
||||
|
||||
bool operator==(const Environment& RHS) const {
|
||||
return SubExprBindings == RHS.SubExprBindings &&
|
||||
BlkExprBindings == RHS.BlkExprBindings;
|
||||
}
|
||||
};
|
||||
|
||||
class EnvironmentManager {
|
||||
private:
|
||||
typedef Environment::BindingsTy::Factory FactoryTy;
|
||||
FactoryTy F;
|
||||
|
||||
public:
|
||||
|
||||
EnvironmentManager(llvm::BumpPtrAllocator& Allocator) : F(Allocator) {}
|
||||
~EnvironmentManager() {}
|
||||
|
||||
/// RemoveBlkExpr - Return a new environment object with the same bindings as
|
||||
/// the provided environment except with any bindings for the provided Stmt*
|
||||
/// removed. This method only removes bindings for block-level expressions.
|
||||
/// Using this method on a non-block level expression will return the
|
||||
/// same environment object.
|
||||
Environment RemoveBlkExpr(const Environment& Env, Stmt* E) {
|
||||
return Environment(Env.SubExprBindings, F.Remove(Env.BlkExprBindings, E));
|
||||
}
|
||||
|
||||
Environment RemoveSubExpr(const Environment& Env, Stmt* E) {
|
||||
return Environment(F.Remove(Env.SubExprBindings, E), Env.BlkExprBindings);
|
||||
}
|
||||
|
||||
Environment AddBlkExpr(const Environment& Env, Stmt* E, SVal V) {
|
||||
return Environment(Env.SubExprBindings, F.Add(Env.BlkExprBindings, E, V));
|
||||
}
|
||||
|
||||
Environment AddSubExpr(const Environment& Env, Stmt* E, SVal V) {
|
||||
return Environment(F.Add(Env.SubExprBindings, E, V), Env.BlkExprBindings);
|
||||
}
|
||||
|
||||
/// RemoveSubExprBindings - Return a new environment object with
|
||||
/// the same bindings as the provided environment except with all the
|
||||
/// subexpression bindings removed.
|
||||
Environment RemoveSubExprBindings(const Environment& Env) {
|
||||
return Environment(F.GetEmptyMap(), Env.BlkExprBindings);
|
||||
}
|
||||
|
||||
Environment getInitialEnvironment() {
|
||||
return Environment(F.GetEmptyMap(), F.GetEmptyMap());
|
||||
}
|
||||
|
||||
Environment BindExpr(const Environment& Env, Stmt* E, SVal V,
|
||||
bool isBlkExpr, bool Invalidate);
|
||||
|
||||
Environment
|
||||
RemoveDeadBindings(Environment Env, Stmt* Loc, SymbolReaper& SymReaper,
|
||||
llvm::SmallVectorImpl<const MemRegion*>& DRoots);
|
||||
|
||||
};
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
#endif
|
||||
@@ -1,528 +0,0 @@
|
||||
//=-- ExplodedGraph.h - Local, Path-Sens. "Exploded Graph" -*- 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 template classes ExplodedNode and ExplodedGraph,
|
||||
// which represent a path-sensitive, intra-procedural "exploded graph."
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSIS_EXPLODEDGRAPH
|
||||
#define LLVM_CLANG_ANALYSIS_EXPLODEDGRAPH
|
||||
|
||||
#include "clang/Analysis/ProgramPoint.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
#include "llvm/ADT/GraphTraits.h"
|
||||
#include "llvm/ADT/DepthFirstIterator.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
class GRCoreEngineImpl;
|
||||
class ExplodedNodeImpl;
|
||||
class CFG;
|
||||
class ASTContext;
|
||||
|
||||
class GRStmtNodeBuilderImpl;
|
||||
class GRBranchNodeBuilderImpl;
|
||||
class GRIndirectGotoNodeBuilderImpl;
|
||||
class GRSwitchNodeBuilderImpl;
|
||||
class GREndPathNodebuilderImpl;
|
||||
|
||||
class ExplodedNodeImpl : public llvm::FoldingSetNode {
|
||||
protected:
|
||||
friend class ExplodedGraphImpl;
|
||||
friend class GRCoreEngineImpl;
|
||||
friend class GRStmtNodeBuilderImpl;
|
||||
friend class GRBranchNodeBuilderImpl;
|
||||
friend class GRIndirectGotoNodeBuilderImpl;
|
||||
friend class GRSwitchNodeBuilderImpl;
|
||||
friend class GREndPathNodeBuilderImpl;
|
||||
|
||||
class NodeGroup {
|
||||
enum { Size1 = 0x0, SizeOther = 0x1, AuxFlag = 0x2, Mask = 0x3 };
|
||||
uintptr_t P;
|
||||
|
||||
unsigned getKind() const {
|
||||
return P & 0x1;
|
||||
}
|
||||
|
||||
void* getPtr() const {
|
||||
assert (!getFlag());
|
||||
return reinterpret_cast<void*>(P & ~Mask);
|
||||
}
|
||||
|
||||
ExplodedNodeImpl* getNode() const {
|
||||
return reinterpret_cast<ExplodedNodeImpl*>(getPtr());
|
||||
}
|
||||
|
||||
public:
|
||||
NodeGroup() : P(0) {}
|
||||
|
||||
~NodeGroup();
|
||||
|
||||
ExplodedNodeImpl** begin() const;
|
||||
|
||||
ExplodedNodeImpl** end() const;
|
||||
|
||||
unsigned size() const;
|
||||
|
||||
bool empty() const { return size() == 0; }
|
||||
|
||||
void addNode(ExplodedNodeImpl* N);
|
||||
|
||||
void setFlag() {
|
||||
assert (P == 0);
|
||||
P = AuxFlag;
|
||||
}
|
||||
|
||||
bool getFlag() const {
|
||||
return P & AuxFlag ? true : false;
|
||||
}
|
||||
};
|
||||
|
||||
/// Location - The program location (within a function body) associated
|
||||
/// with this node.
|
||||
const ProgramPoint Location;
|
||||
|
||||
/// State - The state associated with this node.
|
||||
const void* State;
|
||||
|
||||
/// Preds - The predecessors of this node.
|
||||
NodeGroup Preds;
|
||||
|
||||
/// Succs - The successors of this node.
|
||||
NodeGroup Succs;
|
||||
|
||||
/// Construct a ExplodedNodeImpl with the provided location and state.
|
||||
explicit ExplodedNodeImpl(const ProgramPoint& loc, const void* state)
|
||||
: Location(loc), State(state) {}
|
||||
|
||||
/// addPredeccessor - Adds a predecessor to the current node, and
|
||||
/// in tandem add this node as a successor of the other node.
|
||||
void addPredecessor(ExplodedNodeImpl* V);
|
||||
|
||||
public:
|
||||
|
||||
/// getLocation - Returns the edge associated with the given node.
|
||||
ProgramPoint getLocation() const { return Location; }
|
||||
|
||||
unsigned succ_size() const { return Succs.size(); }
|
||||
unsigned pred_size() const { return Preds.size(); }
|
||||
bool succ_empty() const { return Succs.empty(); }
|
||||
bool pred_empty() const { return Preds.empty(); }
|
||||
|
||||
bool isSink() const { return Succs.getFlag(); }
|
||||
void markAsSink() { Succs.setFlag(); }
|
||||
|
||||
// For debugging.
|
||||
|
||||
public:
|
||||
|
||||
class Auditor {
|
||||
public:
|
||||
virtual ~Auditor();
|
||||
virtual void AddEdge(ExplodedNodeImpl* Src, ExplodedNodeImpl* Dst) = 0;
|
||||
};
|
||||
|
||||
static void SetAuditor(Auditor* A);
|
||||
};
|
||||
|
||||
|
||||
template <typename StateTy>
|
||||
struct GRTrait {
|
||||
static inline void Profile(llvm::FoldingSetNodeID& ID, const StateTy* St) {
|
||||
St->Profile(ID);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <typename StateTy>
|
||||
class ExplodedNode : public ExplodedNodeImpl {
|
||||
public:
|
||||
/// Construct a ExplodedNodeImpl with the given node ID, program edge,
|
||||
/// and state.
|
||||
explicit ExplodedNode(const ProgramPoint& loc, const StateTy* St)
|
||||
: ExplodedNodeImpl(loc, St) {}
|
||||
|
||||
/// getState - Returns the state associated with the node.
|
||||
inline const StateTy* getState() const {
|
||||
return static_cast<const StateTy*>(State);
|
||||
}
|
||||
|
||||
// Profiling (for FoldingSet).
|
||||
|
||||
static inline void Profile(llvm::FoldingSetNodeID& ID,
|
||||
const ProgramPoint& Loc,
|
||||
const StateTy* state) {
|
||||
ID.Add(Loc);
|
||||
GRTrait<StateTy>::Profile(ID, state);
|
||||
}
|
||||
|
||||
inline void Profile(llvm::FoldingSetNodeID& ID) const {
|
||||
Profile(ID, getLocation(), getState());
|
||||
}
|
||||
|
||||
void addPredecessor(ExplodedNode* V) {
|
||||
ExplodedNodeImpl::addPredecessor(V);
|
||||
}
|
||||
|
||||
// Iterators over successor and predecessor vertices.
|
||||
typedef ExplodedNode** succ_iterator;
|
||||
typedef const ExplodedNode* const * const_succ_iterator;
|
||||
typedef ExplodedNode** pred_iterator;
|
||||
typedef const ExplodedNode* const * const_pred_iterator;
|
||||
|
||||
pred_iterator pred_begin() { return (ExplodedNode**) Preds.begin(); }
|
||||
pred_iterator pred_end() { return (ExplodedNode**) Preds.end(); }
|
||||
|
||||
const_pred_iterator pred_begin() const {
|
||||
return const_cast<ExplodedNode*>(this)->pred_begin();
|
||||
}
|
||||
const_pred_iterator pred_end() const {
|
||||
return const_cast<ExplodedNode*>(this)->pred_end();
|
||||
}
|
||||
|
||||
succ_iterator succ_begin() { return (ExplodedNode**) Succs.begin(); }
|
||||
succ_iterator succ_end() { return (ExplodedNode**) Succs.end(); }
|
||||
|
||||
const_succ_iterator succ_begin() const {
|
||||
return const_cast<ExplodedNode*>(this)->succ_begin();
|
||||
}
|
||||
const_succ_iterator succ_end() const {
|
||||
return const_cast<ExplodedNode*>(this)->succ_end();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class ExplodedGraphImpl {
|
||||
protected:
|
||||
friend class GRCoreEngineImpl;
|
||||
friend class GRStmtNodeBuilderImpl;
|
||||
friend class GRBranchNodeBuilderImpl;
|
||||
friend class GRIndirectGotoNodeBuilderImpl;
|
||||
friend class GRSwitchNodeBuilderImpl;
|
||||
friend class GREndPathNodeBuilderImpl;
|
||||
|
||||
// Type definitions.
|
||||
typedef llvm::SmallVector<ExplodedNodeImpl*,2> RootsTy;
|
||||
typedef llvm::SmallVector<ExplodedNodeImpl*,10> EndNodesTy;
|
||||
|
||||
/// Roots - The roots of the simulation graph. Usually there will be only
|
||||
/// one, but clients are free to establish multiple subgraphs within a single
|
||||
/// SimulGraph. Moreover, these subgraphs can often merge when paths from
|
||||
/// different roots reach the same state at the same program location.
|
||||
RootsTy Roots;
|
||||
|
||||
/// EndNodes - The nodes in the simulation graph which have been
|
||||
/// specially marked as the endpoint of an abstract simulation path.
|
||||
EndNodesTy EndNodes;
|
||||
|
||||
/// Allocator - BumpPtrAllocator to create nodes.
|
||||
llvm::BumpPtrAllocator Allocator;
|
||||
|
||||
/// cfg - The CFG associated with this analysis graph.
|
||||
CFG& cfg;
|
||||
|
||||
/// CodeDecl - The declaration containing the code being analyzed. This
|
||||
/// can be a FunctionDecl or and ObjCMethodDecl.
|
||||
Decl& CodeDecl;
|
||||
|
||||
/// Ctx - The ASTContext used to "interpret" CodeDecl.
|
||||
ASTContext& Ctx;
|
||||
|
||||
/// NumNodes - The number of nodes in the graph.
|
||||
unsigned NumNodes;
|
||||
|
||||
/// getNodeImpl - Retrieve the node associated with a (Location,State)
|
||||
/// pair, where 'State' is represented as an opaque void*. This method
|
||||
/// is intended to be used only by GRCoreEngineImpl.
|
||||
virtual ExplodedNodeImpl* getNodeImpl(const ProgramPoint& L,
|
||||
const void* State,
|
||||
bool* IsNew) = 0;
|
||||
|
||||
virtual ExplodedGraphImpl* MakeEmptyGraph() const = 0;
|
||||
|
||||
/// addRoot - Add an untyped node to the set of roots.
|
||||
ExplodedNodeImpl* addRoot(ExplodedNodeImpl* V) {
|
||||
Roots.push_back(V);
|
||||
return V;
|
||||
}
|
||||
|
||||
/// addEndOfPath - Add an untyped node to the set of EOP nodes.
|
||||
ExplodedNodeImpl* addEndOfPath(ExplodedNodeImpl* V) {
|
||||
EndNodes.push_back(V);
|
||||
return V;
|
||||
}
|
||||
|
||||
// ctor.
|
||||
ExplodedGraphImpl(CFG& c, Decl& cd, ASTContext& ctx)
|
||||
: cfg(c), CodeDecl(cd), Ctx(ctx), NumNodes(0) {}
|
||||
|
||||
public:
|
||||
virtual ~ExplodedGraphImpl() {}
|
||||
|
||||
unsigned num_roots() const { return Roots.size(); }
|
||||
unsigned num_eops() const { return EndNodes.size(); }
|
||||
|
||||
bool empty() const { return NumNodes == 0; }
|
||||
unsigned size() const { return NumNodes; }
|
||||
|
||||
llvm::BumpPtrAllocator& getAllocator() { return Allocator; }
|
||||
CFG& getCFG() { return cfg; }
|
||||
ASTContext& getContext() { return Ctx; }
|
||||
|
||||
Decl& getCodeDecl() { return CodeDecl; }
|
||||
const Decl& getCodeDecl() const { return CodeDecl; }
|
||||
|
||||
const FunctionDecl* getFunctionDecl() const {
|
||||
return llvm::dyn_cast<FunctionDecl>(&CodeDecl);
|
||||
}
|
||||
|
||||
ExplodedGraphImpl* Trim(const ExplodedNodeImpl* const * NBeg,
|
||||
const ExplodedNodeImpl* const * NEnd) const;
|
||||
|
||||
};
|
||||
|
||||
template <typename STATE>
|
||||
class ExplodedGraph : public ExplodedGraphImpl {
|
||||
public:
|
||||
typedef STATE StateTy;
|
||||
typedef ExplodedNode<StateTy> NodeTy;
|
||||
typedef llvm::FoldingSet<NodeTy> AllNodesTy;
|
||||
|
||||
protected:
|
||||
/// Nodes - The nodes in the graph.
|
||||
AllNodesTy Nodes;
|
||||
|
||||
protected:
|
||||
virtual ExplodedNodeImpl* getNodeImpl(const ProgramPoint& L,
|
||||
const void* State,
|
||||
bool* IsNew) {
|
||||
|
||||
return getNode(L, static_cast<const StateTy*>(State), IsNew);
|
||||
}
|
||||
|
||||
virtual ExplodedGraphImpl* MakeEmptyGraph() const {
|
||||
return new ExplodedGraph(cfg, CodeDecl, Ctx);
|
||||
}
|
||||
|
||||
public:
|
||||
ExplodedGraph(CFG& c, Decl& cd, ASTContext& ctx)
|
||||
: ExplodedGraphImpl(c, cd, ctx) {}
|
||||
|
||||
/// getNode - Retrieve the node associated with a (Location,State) pair,
|
||||
/// where the 'Location' is a ProgramPoint in the CFG. If no node for
|
||||
/// this pair exists, it is created. IsNew is set to true if
|
||||
/// the node was freshly created.
|
||||
NodeTy* getNode(const ProgramPoint& L, const StateTy* State,
|
||||
bool* IsNew = NULL) {
|
||||
|
||||
// Profile 'State' to determine if we already have an existing node.
|
||||
llvm::FoldingSetNodeID profile;
|
||||
void* InsertPos = 0;
|
||||
|
||||
NodeTy::Profile(profile, L, State);
|
||||
NodeTy* V = Nodes.FindNodeOrInsertPos(profile, InsertPos);
|
||||
|
||||
if (!V) {
|
||||
// Allocate a new node.
|
||||
V = (NodeTy*) Allocator.Allocate<NodeTy>();
|
||||
new (V) NodeTy(L, State);
|
||||
|
||||
// Insert the node into the node set and return it.
|
||||
Nodes.InsertNode(V, InsertPos);
|
||||
|
||||
++NumNodes;
|
||||
|
||||
if (IsNew) *IsNew = true;
|
||||
}
|
||||
else
|
||||
if (IsNew) *IsNew = false;
|
||||
|
||||
return V;
|
||||
}
|
||||
|
||||
// Iterators.
|
||||
typedef NodeTy** roots_iterator;
|
||||
typedef const NodeTy** const_roots_iterator;
|
||||
typedef NodeTy** eop_iterator;
|
||||
typedef const NodeTy** const_eop_iterator;
|
||||
typedef typename AllNodesTy::iterator node_iterator;
|
||||
typedef typename AllNodesTy::const_iterator const_node_iterator;
|
||||
|
||||
node_iterator nodes_begin() {
|
||||
return Nodes.begin();
|
||||
}
|
||||
|
||||
node_iterator nodes_end() {
|
||||
return Nodes.end();
|
||||
}
|
||||
|
||||
const_node_iterator nodes_begin() const {
|
||||
return Nodes.begin();
|
||||
}
|
||||
|
||||
const_node_iterator nodes_end() const {
|
||||
return Nodes.end();
|
||||
}
|
||||
|
||||
roots_iterator roots_begin() {
|
||||
return reinterpret_cast<roots_iterator>(Roots.begin());
|
||||
}
|
||||
|
||||
roots_iterator roots_end() {
|
||||
return reinterpret_cast<roots_iterator>(Roots.end());
|
||||
}
|
||||
|
||||
const_roots_iterator roots_begin() const {
|
||||
return const_cast<ExplodedGraph>(this)->roots_begin();
|
||||
}
|
||||
|
||||
const_roots_iterator roots_end() const {
|
||||
return const_cast<ExplodedGraph>(this)->roots_end();
|
||||
}
|
||||
|
||||
eop_iterator eop_begin() {
|
||||
return reinterpret_cast<eop_iterator>(EndNodes.begin());
|
||||
}
|
||||
|
||||
eop_iterator eop_end() {
|
||||
return reinterpret_cast<eop_iterator>(EndNodes.end());
|
||||
}
|
||||
|
||||
const_eop_iterator eop_begin() const {
|
||||
return const_cast<ExplodedGraph>(this)->eop_begin();
|
||||
}
|
||||
|
||||
const_eop_iterator eop_end() const {
|
||||
return const_cast<ExplodedGraph>(this)->eop_end();
|
||||
}
|
||||
|
||||
// Utility.
|
||||
|
||||
ExplodedGraph*
|
||||
Trim(const NodeTy* const* NBeg, const NodeTy* const* NEnd) const {
|
||||
|
||||
if (NBeg == NEnd)
|
||||
return NULL;
|
||||
|
||||
assert (NBeg < NEnd);
|
||||
|
||||
const ExplodedNodeImpl* const* NBegImpl =
|
||||
(const ExplodedNodeImpl* const*) NBeg;
|
||||
const ExplodedNodeImpl* const* NEndImpl =
|
||||
(const ExplodedNodeImpl* const*) NEnd;
|
||||
|
||||
return static_cast<ExplodedGraph*>(ExplodedGraphImpl::Trim(NBegImpl,
|
||||
NEndImpl));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <typename StateTy>
|
||||
class ExplodedNodeSet {
|
||||
|
||||
typedef ExplodedNode<StateTy> NodeTy;
|
||||
typedef llvm::SmallPtrSet<NodeTy*,5> ImplTy;
|
||||
ImplTy Impl;
|
||||
|
||||
public:
|
||||
ExplodedNodeSet(NodeTy* N) {
|
||||
assert (N && !static_cast<ExplodedNodeImpl*>(N)->isSink());
|
||||
Impl.insert(N);
|
||||
}
|
||||
|
||||
ExplodedNodeSet() {}
|
||||
|
||||
inline void Add(NodeTy* N) {
|
||||
if (N && !static_cast<ExplodedNodeImpl*>(N)->isSink()) Impl.insert(N);
|
||||
}
|
||||
|
||||
typedef typename ImplTy::iterator iterator;
|
||||
typedef typename ImplTy::const_iterator const_iterator;
|
||||
|
||||
inline unsigned size() const { return Impl.size(); }
|
||||
inline bool empty() const { return Impl.empty(); }
|
||||
|
||||
inline void clear() { Impl.clear(); }
|
||||
|
||||
inline iterator begin() { return Impl.begin(); }
|
||||
inline iterator end() { return Impl.end(); }
|
||||
|
||||
inline const_iterator begin() const { return Impl.begin(); }
|
||||
inline const_iterator end() const { return Impl.end(); }
|
||||
};
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
// GraphTraits
|
||||
|
||||
namespace llvm {
|
||||
template<typename StateTy>
|
||||
struct GraphTraits<clang::ExplodedNode<StateTy>*> {
|
||||
typedef clang::ExplodedNode<StateTy> NodeType;
|
||||
typedef typename NodeType::succ_iterator ChildIteratorType;
|
||||
typedef llvm::df_iterator<NodeType*> nodes_iterator;
|
||||
|
||||
static inline NodeType* getEntryNode(NodeType* N) {
|
||||
return N;
|
||||
}
|
||||
|
||||
static inline ChildIteratorType child_begin(NodeType* N) {
|
||||
return N->succ_begin();
|
||||
}
|
||||
|
||||
static inline ChildIteratorType child_end(NodeType* N) {
|
||||
return N->succ_end();
|
||||
}
|
||||
|
||||
static inline nodes_iterator nodes_begin(NodeType* N) {
|
||||
return df_begin(N);
|
||||
}
|
||||
|
||||
static inline nodes_iterator nodes_end(NodeType* N) {
|
||||
return df_end(N);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename StateTy>
|
||||
struct GraphTraits<const clang::ExplodedNode<StateTy>*> {
|
||||
typedef const clang::ExplodedNode<StateTy> NodeType;
|
||||
typedef typename NodeType::succ_iterator ChildIteratorType;
|
||||
typedef llvm::df_iterator<NodeType*> nodes_iterator;
|
||||
|
||||
static inline NodeType* getEntryNode(NodeType* N) {
|
||||
return N;
|
||||
}
|
||||
|
||||
static inline ChildIteratorType child_begin(NodeType* N) {
|
||||
return N->succ_begin();
|
||||
}
|
||||
|
||||
static inline ChildIteratorType child_end(NodeType* N) {
|
||||
return N->succ_end();
|
||||
}
|
||||
|
||||
static inline nodes_iterator nodes_begin(NodeType* N) {
|
||||
return df_begin(N);
|
||||
}
|
||||
|
||||
static inline nodes_iterator nodes_end(NodeType* N) {
|
||||
return df_end(N);
|
||||
}
|
||||
};
|
||||
|
||||
} // end llvm namespace
|
||||
|
||||
#endif
|
||||
@@ -1,39 +0,0 @@
|
||||
//==- GRAuditor.h - Observers of the creation of ExplodedNodes------*- 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 GRAuditor and its primary subclasses, an interface
|
||||
// to audit the creation of ExplodedNodes. This interface can be used
|
||||
// to implement simple checkers that do not mutate analysis state but
|
||||
// instead operate by perfoming simple logical checks at key monitoring
|
||||
// locations (e.g., function calls).
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSIS_GRAUDITOR
|
||||
#define LLVM_CLANG_ANALYSIS_GRAUDITOR
|
||||
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "clang/Analysis/PathSensitive/ExplodedGraph.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
template <typename STATE>
|
||||
class GRAuditor {
|
||||
public:
|
||||
typedef ExplodedNode<STATE> NodeTy;
|
||||
typedef typename STATE::ManagerTy ManagerTy;
|
||||
|
||||
virtual ~GRAuditor() {}
|
||||
virtual bool Audit(NodeTy* N, ManagerTy& M) = 0;
|
||||
};
|
||||
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
#endif
|
||||
@@ -1,50 +0,0 @@
|
||||
//==- GRBlockCounter.h - ADT for counting block visits -------------*- 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 GRBlockCounter, an abstract data type used to count
|
||||
// the number of times a given block has been visited along a path
|
||||
// analyzed by GRCoreEngine.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSIS_GRBLOCKCOUNTER
|
||||
#define LLVM_CLANG_ANALYSIS_GRBLOCKCOUNTER
|
||||
|
||||
namespace llvm {
|
||||
class BumpPtrAllocator;
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
|
||||
class GRBlockCounter {
|
||||
void* Data;
|
||||
|
||||
GRBlockCounter(void* D) : Data(D) {}
|
||||
|
||||
public:
|
||||
GRBlockCounter() : Data(0) {}
|
||||
|
||||
unsigned getNumVisited(unsigned BlockID) const;
|
||||
|
||||
class Factory {
|
||||
void* F;
|
||||
public:
|
||||
Factory(llvm::BumpPtrAllocator& Alloc);
|
||||
~Factory();
|
||||
|
||||
GRBlockCounter GetEmptyCounter();
|
||||
GRBlockCounter IncrementCount(GRBlockCounter BC, unsigned BlockID);
|
||||
};
|
||||
|
||||
friend class Factory;
|
||||
};
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
#endif
|
||||
@@ -1,644 +0,0 @@
|
||||
//==- GRCoreEngine.h - Path-Sensitive Dataflow Engine ------------------*- C++ -*-//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines a generic engine for intraprocedural, path-sensitive,
|
||||
// dataflow analysis via graph reachability.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSIS_GRENGINE
|
||||
#define LLVM_CLANG_ANALYSIS_GRENGINE
|
||||
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "clang/Analysis/PathSensitive/ExplodedGraph.h"
|
||||
#include "clang/Analysis/PathSensitive/GRWorkList.h"
|
||||
#include "clang/Analysis/PathSensitive/GRBlockCounter.h"
|
||||
#include "clang/Analysis/PathSensitive/GRAuditor.h"
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
class GRStmtNodeBuilderImpl;
|
||||
class GRBranchNodeBuilderImpl;
|
||||
class GRIndirectGotoNodeBuilderImpl;
|
||||
class GRSwitchNodeBuilderImpl;
|
||||
class GREndPathNodeBuilderImpl;
|
||||
class GRWorkList;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// GRCoreEngineImpl - Implements the core logic of the graph-reachability
|
||||
/// analysis. It traverses the CFG and generates the ExplodedGraph.
|
||||
/// Program "states" are treated as opaque void pointers.
|
||||
/// The template class GRCoreEngine (which subclasses GRCoreEngineImpl)
|
||||
/// provides the matching component to the engine that knows the actual types
|
||||
/// for states. Note that this engine only dispatches to transfer functions
|
||||
/// at the statement and block-level. The analyses themselves must implement
|
||||
/// any transfer function logic and the sub-expression level (if any).
|
||||
class GRCoreEngineImpl {
|
||||
protected:
|
||||
friend class GRStmtNodeBuilderImpl;
|
||||
friend class GRBranchNodeBuilderImpl;
|
||||
friend class GRIndirectGotoNodeBuilderImpl;
|
||||
friend class GRSwitchNodeBuilderImpl;
|
||||
friend class GREndPathNodeBuilderImpl;
|
||||
|
||||
/// G - The simulation graph. Each node is a (location,state) pair.
|
||||
llvm::OwningPtr<ExplodedGraphImpl> G;
|
||||
|
||||
/// WList - A set of queued nodes that need to be processed by the
|
||||
/// worklist algorithm. It is up to the implementation of WList to decide
|
||||
/// the order that nodes are processed.
|
||||
GRWorkList* WList;
|
||||
|
||||
/// BCounterFactory - A factory object for created GRBlockCounter objects.
|
||||
/// These are used to record for key nodes in the ExplodedGraph the
|
||||
/// number of times different CFGBlocks have been visited along a path.
|
||||
GRBlockCounter::Factory BCounterFactory;
|
||||
|
||||
void GenerateNode(const ProgramPoint& Loc, const void* State,
|
||||
ExplodedNodeImpl* Pred);
|
||||
|
||||
/// getInitialState - Gets the void* representing the initial 'state'
|
||||
/// of the analysis. This is simply a wrapper (implemented
|
||||
/// in GRCoreEngine) that performs type erasure on the initial
|
||||
/// state returned by the checker object.
|
||||
virtual const void* getInitialState() = 0;
|
||||
|
||||
void HandleBlockEdge(const BlockEdge& E, ExplodedNodeImpl* Pred);
|
||||
void HandleBlockEntrance(const BlockEntrance& E, ExplodedNodeImpl* Pred);
|
||||
void HandleBlockExit(CFGBlock* B, ExplodedNodeImpl* Pred);
|
||||
void HandlePostStmt(const PostStmt& S, CFGBlock* B,
|
||||
unsigned StmtIdx, ExplodedNodeImpl *Pred);
|
||||
|
||||
void HandleBranch(Stmt* Cond, Stmt* Term, CFGBlock* B,
|
||||
ExplodedNodeImpl* Pred);
|
||||
|
||||
virtual void ProcessEndPath(GREndPathNodeBuilderImpl& Builder) = 0;
|
||||
|
||||
virtual bool ProcessBlockEntrance(CFGBlock* Blk, const void* State,
|
||||
GRBlockCounter BC) = 0;
|
||||
|
||||
virtual void ProcessStmt(Stmt* S, GRStmtNodeBuilderImpl& Builder) = 0;
|
||||
|
||||
virtual void ProcessBranch(Stmt* Condition, Stmt* Terminator,
|
||||
GRBranchNodeBuilderImpl& Builder) = 0;
|
||||
|
||||
virtual void ProcessIndirectGoto(GRIndirectGotoNodeBuilderImpl& Builder) = 0;
|
||||
|
||||
virtual void ProcessSwitch(GRSwitchNodeBuilderImpl& Builder) = 0;
|
||||
|
||||
private:
|
||||
GRCoreEngineImpl(const GRCoreEngineImpl&); // Do not implement.
|
||||
GRCoreEngineImpl& operator=(const GRCoreEngineImpl&);
|
||||
|
||||
protected:
|
||||
GRCoreEngineImpl(ExplodedGraphImpl* g, GRWorkList* wl)
|
||||
: G(g), WList(wl), BCounterFactory(g->getAllocator()) {}
|
||||
|
||||
public:
|
||||
/// ExecuteWorkList - Run the worklist algorithm for a maximum number of
|
||||
/// steps. Returns true if there is still simulation state on the worklist.
|
||||
bool ExecuteWorkList(unsigned Steps);
|
||||
|
||||
virtual ~GRCoreEngineImpl();
|
||||
|
||||
CFG& getCFG() { return G->getCFG(); }
|
||||
};
|
||||
|
||||
class GRStmtNodeBuilderImpl {
|
||||
GRCoreEngineImpl& Eng;
|
||||
CFGBlock& B;
|
||||
const unsigned Idx;
|
||||
ExplodedNodeImpl* Pred;
|
||||
ExplodedNodeImpl* LastNode;
|
||||
|
||||
typedef llvm::SmallPtrSet<ExplodedNodeImpl*,5> DeferredTy;
|
||||
DeferredTy Deferred;
|
||||
|
||||
void GenerateAutoTransition(ExplodedNodeImpl* N);
|
||||
|
||||
public:
|
||||
GRStmtNodeBuilderImpl(CFGBlock* b, unsigned idx,
|
||||
ExplodedNodeImpl* N, GRCoreEngineImpl* e);
|
||||
|
||||
~GRStmtNodeBuilderImpl();
|
||||
|
||||
ExplodedNodeImpl* getBasePredecessor() const { return Pred; }
|
||||
|
||||
ExplodedNodeImpl* getLastNode() const {
|
||||
return LastNode ? (LastNode->isSink() ? NULL : LastNode) : NULL;
|
||||
}
|
||||
|
||||
GRBlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter();}
|
||||
|
||||
unsigned getCurrentBlockCount() const {
|
||||
return getBlockCounter().getNumVisited(B.getBlockID());
|
||||
}
|
||||
|
||||
ExplodedNodeImpl*
|
||||
generateNodeImpl(Stmt* S, const void* State, ExplodedNodeImpl* Pred,
|
||||
ProgramPoint::Kind K = ProgramPoint::PostStmtKind);
|
||||
|
||||
ExplodedNodeImpl*
|
||||
generateNodeImpl(Stmt* S, const void* State,
|
||||
ProgramPoint::Kind K = ProgramPoint::PostStmtKind) {
|
||||
ExplodedNodeImpl* N = getLastNode();
|
||||
assert (N && "Predecessor of new node is infeasible.");
|
||||
return generateNodeImpl(S, State, N, K);
|
||||
}
|
||||
|
||||
/// getStmt - Return the current block-level expression associated with
|
||||
/// this builder.
|
||||
Stmt* getStmt() const { return B[Idx]; }
|
||||
|
||||
/// getBlock - Return the CFGBlock associated with the block-level expression
|
||||
/// of this builder.
|
||||
CFGBlock* getBlock() const { return &B; }
|
||||
};
|
||||
|
||||
|
||||
template<typename STATE>
|
||||
class GRStmtNodeBuilder {
|
||||
public:
|
||||
typedef STATE StateTy;
|
||||
typedef typename StateTy::ManagerTy StateManagerTy;
|
||||
typedef ExplodedNode<StateTy> NodeTy;
|
||||
|
||||
private:
|
||||
GRStmtNodeBuilderImpl& NB;
|
||||
StateManagerTy& Mgr;
|
||||
const StateTy* CleanedState;
|
||||
GRAuditor<StateTy>* Auditor;
|
||||
|
||||
public:
|
||||
GRStmtNodeBuilder(GRStmtNodeBuilderImpl& nb, StateManagerTy& mgr) :
|
||||
NB(nb), Mgr(mgr), Auditor(0), PurgingDeadSymbols(false),
|
||||
BuildSinks(false), HasGeneratedNode(false),
|
||||
PointKind(ProgramPoint::PostStmtKind) {
|
||||
|
||||
CleanedState = getLastNode()->getState();
|
||||
}
|
||||
|
||||
void setAuditor(GRAuditor<StateTy>* A) {
|
||||
Auditor = A;
|
||||
}
|
||||
|
||||
NodeTy* getLastNode() const {
|
||||
return static_cast<NodeTy*>(NB.getLastNode());
|
||||
}
|
||||
|
||||
NodeTy* generateNode(Stmt* S, const StateTy* St, NodeTy* Pred,
|
||||
ProgramPoint::Kind K) {
|
||||
HasGeneratedNode = true;
|
||||
if (PurgingDeadSymbols) K = ProgramPoint::PostPurgeDeadSymbolsKind;
|
||||
return static_cast<NodeTy*>(NB.generateNodeImpl(S, St, Pred, K));
|
||||
}
|
||||
|
||||
NodeTy* generateNode(Stmt* S, const StateTy* St, NodeTy* Pred) {
|
||||
return generateNode(S, St, Pred, PointKind);
|
||||
}
|
||||
|
||||
NodeTy* generateNode(Stmt* S, const StateTy* St, ProgramPoint::Kind K) {
|
||||
HasGeneratedNode = true;
|
||||
if (PurgingDeadSymbols) K = ProgramPoint::PostPurgeDeadSymbolsKind;
|
||||
return static_cast<NodeTy*>(NB.generateNodeImpl(S, St, K));
|
||||
}
|
||||
|
||||
NodeTy* generateNode(Stmt* S, const StateTy* St) {
|
||||
return generateNode(S, St, PointKind);
|
||||
}
|
||||
|
||||
|
||||
GRBlockCounter getBlockCounter() const {
|
||||
return NB.getBlockCounter();
|
||||
}
|
||||
|
||||
unsigned getCurrentBlockCount() const {
|
||||
return NB.getCurrentBlockCount();
|
||||
}
|
||||
|
||||
const StateTy* GetState(NodeTy* Pred) const {
|
||||
if ((ExplodedNodeImpl*) Pred == NB.getBasePredecessor())
|
||||
return CleanedState;
|
||||
else
|
||||
return Pred->getState();
|
||||
}
|
||||
|
||||
void SetCleanedState(const StateTy* St) {
|
||||
CleanedState = St;
|
||||
}
|
||||
|
||||
NodeTy* MakeNode(ExplodedNodeSet<StateTy>& Dst, Stmt* S,
|
||||
NodeTy* Pred, const StateTy* St) {
|
||||
return MakeNode(Dst, S, Pred, St, PointKind);
|
||||
}
|
||||
|
||||
NodeTy* MakeNode(ExplodedNodeSet<StateTy>& Dst, Stmt* S,
|
||||
NodeTy* Pred, const StateTy* St, ProgramPoint::Kind K) {
|
||||
|
||||
const StateTy* PredState = GetState(Pred);
|
||||
|
||||
// If the state hasn't changed, don't generate a new node.
|
||||
if (!BuildSinks && St == PredState && Auditor == 0) {
|
||||
Dst.Add(Pred);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
NodeTy* N = generateNode(S, St, Pred, K);
|
||||
|
||||
if (N) {
|
||||
if (BuildSinks)
|
||||
N->markAsSink();
|
||||
else {
|
||||
if (Auditor && Auditor->Audit(N, Mgr))
|
||||
N->markAsSink();
|
||||
|
||||
Dst.Add(N);
|
||||
}
|
||||
}
|
||||
|
||||
return N;
|
||||
}
|
||||
|
||||
NodeTy* MakeSinkNode(ExplodedNodeSet<StateTy>& Dst, Stmt* S,
|
||||
NodeTy* Pred, const StateTy* St) {
|
||||
bool Tmp = BuildSinks;
|
||||
BuildSinks = true;
|
||||
NodeTy* N = MakeNode(Dst, S, Pred, St);
|
||||
BuildSinks = Tmp;
|
||||
return N;
|
||||
}
|
||||
|
||||
bool PurgingDeadSymbols;
|
||||
bool BuildSinks;
|
||||
bool HasGeneratedNode;
|
||||
ProgramPoint::Kind PointKind;
|
||||
};
|
||||
|
||||
class GRBranchNodeBuilderImpl {
|
||||
GRCoreEngineImpl& Eng;
|
||||
CFGBlock* Src;
|
||||
CFGBlock* DstT;
|
||||
CFGBlock* DstF;
|
||||
ExplodedNodeImpl* Pred;
|
||||
|
||||
typedef llvm::SmallVector<ExplodedNodeImpl*,3> DeferredTy;
|
||||
DeferredTy Deferred;
|
||||
|
||||
bool GeneratedTrue;
|
||||
bool GeneratedFalse;
|
||||
|
||||
public:
|
||||
GRBranchNodeBuilderImpl(CFGBlock* src, CFGBlock* dstT, CFGBlock* dstF,
|
||||
ExplodedNodeImpl* pred, GRCoreEngineImpl* e)
|
||||
: Eng(*e), Src(src), DstT(dstT), DstF(dstF), Pred(pred),
|
||||
GeneratedTrue(false), GeneratedFalse(false) {}
|
||||
|
||||
~GRBranchNodeBuilderImpl();
|
||||
|
||||
ExplodedNodeImpl* getPredecessor() const { return Pred; }
|
||||
const ExplodedGraphImpl& getGraph() const { return *Eng.G; }
|
||||
GRBlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter();}
|
||||
|
||||
ExplodedNodeImpl* generateNodeImpl(const void* State, bool branch);
|
||||
|
||||
CFGBlock* getTargetBlock(bool branch) const {
|
||||
return branch ? DstT : DstF;
|
||||
}
|
||||
|
||||
void markInfeasible(bool branch) {
|
||||
if (branch) GeneratedTrue = true;
|
||||
else GeneratedFalse = true;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename STATE>
|
||||
class GRBranchNodeBuilder {
|
||||
typedef STATE StateTy;
|
||||
typedef ExplodedGraph<StateTy> GraphTy;
|
||||
typedef typename GraphTy::NodeTy NodeTy;
|
||||
|
||||
GRBranchNodeBuilderImpl& NB;
|
||||
|
||||
public:
|
||||
GRBranchNodeBuilder(GRBranchNodeBuilderImpl& nb) : NB(nb) {}
|
||||
|
||||
const GraphTy& getGraph() const {
|
||||
return static_cast<const GraphTy&>(NB.getGraph());
|
||||
}
|
||||
|
||||
NodeTy* getPredecessor() const {
|
||||
return static_cast<NodeTy*>(NB.getPredecessor());
|
||||
}
|
||||
|
||||
const StateTy* getState() const {
|
||||
return getPredecessor()->getState();
|
||||
}
|
||||
|
||||
NodeTy* generateNode(const StateTy* St, bool branch) {
|
||||
return static_cast<NodeTy*>(NB.generateNodeImpl(St, branch));
|
||||
}
|
||||
|
||||
GRBlockCounter getBlockCounter() const {
|
||||
return NB.getBlockCounter();
|
||||
}
|
||||
|
||||
CFGBlock* getTargetBlock(bool branch) const {
|
||||
return NB.getTargetBlock(branch);
|
||||
}
|
||||
|
||||
void markInfeasible(bool branch) {
|
||||
NB.markInfeasible(branch);
|
||||
}
|
||||
};
|
||||
|
||||
class GRIndirectGotoNodeBuilderImpl {
|
||||
GRCoreEngineImpl& Eng;
|
||||
CFGBlock* Src;
|
||||
CFGBlock& DispatchBlock;
|
||||
Expr* E;
|
||||
ExplodedNodeImpl* Pred;
|
||||
public:
|
||||
GRIndirectGotoNodeBuilderImpl(ExplodedNodeImpl* pred, CFGBlock* src,
|
||||
Expr* e, CFGBlock* dispatch,
|
||||
GRCoreEngineImpl* eng)
|
||||
: Eng(*eng), Src(src), DispatchBlock(*dispatch), E(e), Pred(pred) {}
|
||||
|
||||
|
||||
class Iterator {
|
||||
CFGBlock::succ_iterator I;
|
||||
|
||||
friend class GRIndirectGotoNodeBuilderImpl;
|
||||
Iterator(CFGBlock::succ_iterator i) : I(i) {}
|
||||
public:
|
||||
|
||||
Iterator& operator++() { ++I; return *this; }
|
||||
bool operator!=(const Iterator& X) const { return I != X.I; }
|
||||
|
||||
LabelStmt* getLabel() const {
|
||||
return llvm::cast<LabelStmt>((*I)->getLabel());
|
||||
}
|
||||
|
||||
CFGBlock* getBlock() const {
|
||||
return *I;
|
||||
}
|
||||
};
|
||||
|
||||
Iterator begin() { return Iterator(DispatchBlock.succ_begin()); }
|
||||
Iterator end() { return Iterator(DispatchBlock.succ_end()); }
|
||||
|
||||
ExplodedNodeImpl* generateNodeImpl(const Iterator& I, const void* State,
|
||||
bool isSink);
|
||||
|
||||
Expr* getTarget() const { return E; }
|
||||
const void* getState() const { return Pred->State; }
|
||||
};
|
||||
|
||||
template<typename STATE>
|
||||
class GRIndirectGotoNodeBuilder {
|
||||
typedef STATE StateTy;
|
||||
typedef ExplodedGraph<StateTy> GraphTy;
|
||||
typedef typename GraphTy::NodeTy NodeTy;
|
||||
|
||||
GRIndirectGotoNodeBuilderImpl& NB;
|
||||
|
||||
public:
|
||||
GRIndirectGotoNodeBuilder(GRIndirectGotoNodeBuilderImpl& nb) : NB(nb) {}
|
||||
|
||||
typedef GRIndirectGotoNodeBuilderImpl::Iterator iterator;
|
||||
|
||||
iterator begin() { return NB.begin(); }
|
||||
iterator end() { return NB.end(); }
|
||||
|
||||
Expr* getTarget() const { return NB.getTarget(); }
|
||||
|
||||
NodeTy* generateNode(const iterator& I, const StateTy* St, bool isSink=false){
|
||||
return static_cast<NodeTy*>(NB.generateNodeImpl(I, St, isSink));
|
||||
}
|
||||
|
||||
const StateTy* getState() const {
|
||||
return static_cast<const StateTy*>(NB.getState());
|
||||
}
|
||||
};
|
||||
|
||||
class GRSwitchNodeBuilderImpl {
|
||||
GRCoreEngineImpl& Eng;
|
||||
CFGBlock* Src;
|
||||
Expr* Condition;
|
||||
ExplodedNodeImpl* Pred;
|
||||
public:
|
||||
GRSwitchNodeBuilderImpl(ExplodedNodeImpl* pred, CFGBlock* src,
|
||||
Expr* condition, GRCoreEngineImpl* eng)
|
||||
: Eng(*eng), Src(src), Condition(condition), Pred(pred) {}
|
||||
|
||||
class Iterator {
|
||||
CFGBlock::succ_reverse_iterator I;
|
||||
|
||||
friend class GRSwitchNodeBuilderImpl;
|
||||
Iterator(CFGBlock::succ_reverse_iterator i) : I(i) {}
|
||||
public:
|
||||
|
||||
Iterator& operator++() { ++I; return *this; }
|
||||
bool operator!=(const Iterator& X) const { return I != X.I; }
|
||||
|
||||
CaseStmt* getCase() const {
|
||||
return llvm::cast<CaseStmt>((*I)->getLabel());
|
||||
}
|
||||
|
||||
CFGBlock* getBlock() const {
|
||||
return *I;
|
||||
}
|
||||
};
|
||||
|
||||
Iterator begin() { return Iterator(Src->succ_rbegin()+1); }
|
||||
Iterator end() { return Iterator(Src->succ_rend()); }
|
||||
|
||||
ExplodedNodeImpl* generateCaseStmtNodeImpl(const Iterator& I,
|
||||
const void* State);
|
||||
|
||||
ExplodedNodeImpl* generateDefaultCaseNodeImpl(const void* State,
|
||||
bool isSink);
|
||||
|
||||
Expr* getCondition() const { return Condition; }
|
||||
const void* getState() const { return Pred->State; }
|
||||
};
|
||||
|
||||
template<typename STATE>
|
||||
class GRSwitchNodeBuilder {
|
||||
typedef STATE StateTy;
|
||||
typedef ExplodedGraph<StateTy> GraphTy;
|
||||
typedef typename GraphTy::NodeTy NodeTy;
|
||||
|
||||
GRSwitchNodeBuilderImpl& NB;
|
||||
|
||||
public:
|
||||
GRSwitchNodeBuilder(GRSwitchNodeBuilderImpl& nb) : NB(nb) {}
|
||||
|
||||
typedef GRSwitchNodeBuilderImpl::Iterator iterator;
|
||||
|
||||
iterator begin() { return NB.begin(); }
|
||||
iterator end() { return NB.end(); }
|
||||
|
||||
Expr* getCondition() const { return NB.getCondition(); }
|
||||
|
||||
NodeTy* generateCaseStmtNode(const iterator& I, const StateTy* St) {
|
||||
return static_cast<NodeTy*>(NB.generateCaseStmtNodeImpl(I, St));
|
||||
}
|
||||
|
||||
NodeTy* generateDefaultCaseNode(const StateTy* St, bool isSink = false) {
|
||||
return static_cast<NodeTy*>(NB.generateDefaultCaseNodeImpl(St, isSink));
|
||||
}
|
||||
|
||||
const StateTy* getState() const {
|
||||
return static_cast<const StateTy*>(NB.getState());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class GREndPathNodeBuilderImpl {
|
||||
GRCoreEngineImpl& Eng;
|
||||
CFGBlock& B;
|
||||
ExplodedNodeImpl* Pred;
|
||||
bool HasGeneratedNode;
|
||||
|
||||
public:
|
||||
GREndPathNodeBuilderImpl(CFGBlock* b, ExplodedNodeImpl* N,
|
||||
GRCoreEngineImpl* e)
|
||||
: Eng(*e), B(*b), Pred(N), HasGeneratedNode(false) {}
|
||||
|
||||
~GREndPathNodeBuilderImpl();
|
||||
|
||||
ExplodedNodeImpl* getPredecessor() const { return Pred; }
|
||||
|
||||
GRBlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter();}
|
||||
|
||||
unsigned getCurrentBlockCount() const {
|
||||
return getBlockCounter().getNumVisited(B.getBlockID());
|
||||
}
|
||||
|
||||
ExplodedNodeImpl* generateNodeImpl(const void* State);
|
||||
|
||||
CFGBlock* getBlock() const { return &B; }
|
||||
};
|
||||
|
||||
|
||||
template<typename STATE>
|
||||
class GREndPathNodeBuilder {
|
||||
typedef STATE StateTy;
|
||||
typedef ExplodedNode<StateTy> NodeTy;
|
||||
|
||||
GREndPathNodeBuilderImpl& NB;
|
||||
|
||||
public:
|
||||
GREndPathNodeBuilder(GREndPathNodeBuilderImpl& nb) : NB(nb) {}
|
||||
|
||||
NodeTy* getPredecessor() const {
|
||||
return static_cast<NodeTy*>(NB.getPredecessor());
|
||||
}
|
||||
|
||||
GRBlockCounter getBlockCounter() const {
|
||||
return NB.getBlockCounter();
|
||||
}
|
||||
|
||||
unsigned getCurrentBlockCount() const {
|
||||
return NB.getCurrentBlockCount();
|
||||
}
|
||||
|
||||
const StateTy* getState() const {
|
||||
return getPredecessor()->getState();
|
||||
}
|
||||
|
||||
NodeTy* MakeNode(const StateTy* St) {
|
||||
return static_cast<NodeTy*>(NB.generateNodeImpl(St));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename SUBENGINE>
|
||||
class GRCoreEngine : public GRCoreEngineImpl {
|
||||
public:
|
||||
typedef SUBENGINE SubEngineTy;
|
||||
typedef typename SubEngineTy::StateTy StateTy;
|
||||
typedef typename StateTy::ManagerTy StateManagerTy;
|
||||
typedef ExplodedGraph<StateTy> GraphTy;
|
||||
typedef typename GraphTy::NodeTy NodeTy;
|
||||
|
||||
protected:
|
||||
SubEngineTy& SubEngine;
|
||||
|
||||
virtual const void* getInitialState() {
|
||||
return SubEngine.getInitialState();
|
||||
}
|
||||
|
||||
virtual void ProcessEndPath(GREndPathNodeBuilderImpl& BuilderImpl) {
|
||||
GREndPathNodeBuilder<StateTy> Builder(BuilderImpl);
|
||||
SubEngine.ProcessEndPath(Builder);
|
||||
}
|
||||
|
||||
virtual void ProcessStmt(Stmt* S, GRStmtNodeBuilderImpl& BuilderImpl) {
|
||||
GRStmtNodeBuilder<StateTy> Builder(BuilderImpl,SubEngine.getStateManager());
|
||||
SubEngine.ProcessStmt(S, Builder);
|
||||
}
|
||||
|
||||
virtual bool ProcessBlockEntrance(CFGBlock* Blk, const void* State,
|
||||
GRBlockCounter BC) {
|
||||
return SubEngine.ProcessBlockEntrance(Blk,
|
||||
static_cast<const StateTy*>(State),
|
||||
BC);
|
||||
}
|
||||
|
||||
virtual void ProcessBranch(Stmt* Condition, Stmt* Terminator,
|
||||
GRBranchNodeBuilderImpl& BuilderImpl) {
|
||||
GRBranchNodeBuilder<StateTy> Builder(BuilderImpl);
|
||||
SubEngine.ProcessBranch(Condition, Terminator, Builder);
|
||||
}
|
||||
|
||||
virtual void ProcessIndirectGoto(GRIndirectGotoNodeBuilderImpl& BuilderImpl) {
|
||||
GRIndirectGotoNodeBuilder<StateTy> Builder(BuilderImpl);
|
||||
SubEngine.ProcessIndirectGoto(Builder);
|
||||
}
|
||||
|
||||
virtual void ProcessSwitch(GRSwitchNodeBuilderImpl& BuilderImpl) {
|
||||
GRSwitchNodeBuilder<StateTy> Builder(BuilderImpl);
|
||||
SubEngine.ProcessSwitch(Builder);
|
||||
}
|
||||
|
||||
public:
|
||||
/// Construct a GRCoreEngine object to analyze the provided CFG using
|
||||
/// a DFS exploration of the exploded graph.
|
||||
GRCoreEngine(CFG& cfg, Decl& cd, ASTContext& ctx, SubEngineTy& subengine)
|
||||
: GRCoreEngineImpl(new GraphTy(cfg, cd, ctx),
|
||||
GRWorkList::MakeBFSBlockDFSContents()),
|
||||
SubEngine(subengine) {}
|
||||
|
||||
/// Construct a GRCoreEngine object to analyze the provided CFG and to
|
||||
/// use the provided worklist object to execute the worklist algorithm.
|
||||
/// The GRCoreEngine object assumes ownership of 'wlist'.
|
||||
GRCoreEngine(CFG& cfg, Decl& cd, ASTContext& ctx, GRWorkList* wlist,
|
||||
SubEngineTy& subengine)
|
||||
: GRCoreEngineImpl(new GraphTy(cfg, cd, ctx), wlist),
|
||||
SubEngine(subengine) {}
|
||||
|
||||
virtual ~GRCoreEngine() {}
|
||||
|
||||
/// getGraph - Returns the exploded graph.
|
||||
GraphTy& getGraph() {
|
||||
return *static_cast<GraphTy*>(G.get());
|
||||
}
|
||||
|
||||
/// takeGraph - Returns the exploded graph. Ownership of the graph is
|
||||
/// transfered to the caller.
|
||||
GraphTy* takeGraph() {
|
||||
return static_cast<GraphTy*>(G.take());
|
||||
}
|
||||
};
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
#endif
|
||||
@@ -1,676 +0,0 @@
|
||||
//===-- GRExprEngine.h - Path-Sensitive Expression-Level Dataflow ---*- C++ -*-=
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines a meta-engine for path-sensitive dataflow analysis that
|
||||
// is built on GREngine, but provides the boilerplate to execute transfer
|
||||
// functions and build the ExplodedGraph at the expression level.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSIS_GREXPRENGINE
|
||||
#define LLVM_CLANG_ANALYSIS_GREXPRENGINE
|
||||
|
||||
#include "clang/Analysis/PathSensitive/GRCoreEngine.h"
|
||||
#include "clang/Analysis/PathSensitive/GRState.h"
|
||||
#include "clang/Analysis/PathSensitive/GRSimpleAPICheck.h"
|
||||
#include "clang/Analysis/PathSensitive/GRTransferFuncs.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/AST/ExprObjC.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
class BugType;
|
||||
class PathDiagnosticClient;
|
||||
class Diagnostic;
|
||||
class BugReporterData;
|
||||
|
||||
class GRExprEngine {
|
||||
|
||||
public:
|
||||
typedef GRState StateTy;
|
||||
typedef ExplodedGraph<StateTy> GraphTy;
|
||||
typedef GraphTy::NodeTy NodeTy;
|
||||
|
||||
// Builders.
|
||||
typedef GRStmtNodeBuilder<StateTy> StmtNodeBuilder;
|
||||
typedef GRBranchNodeBuilder<StateTy> BranchNodeBuilder;
|
||||
typedef GRIndirectGotoNodeBuilder<StateTy> IndirectGotoNodeBuilder;
|
||||
typedef GRSwitchNodeBuilder<StateTy> SwitchNodeBuilder;
|
||||
typedef GREndPathNodeBuilder<StateTy> EndPathNodeBuilder;
|
||||
typedef ExplodedNodeSet<StateTy> NodeSet;
|
||||
|
||||
|
||||
protected:
|
||||
GRCoreEngine<GRExprEngine> CoreEngine;
|
||||
|
||||
/// G - the simulation graph.
|
||||
GraphTy& G;
|
||||
|
||||
/// Liveness - live-variables information the ValueDecl* and block-level
|
||||
/// Expr* in the CFG. Used to prune out dead state.
|
||||
LiveVariables& Liveness;
|
||||
|
||||
/// Builder - The current GRStmtNodeBuilder which is used when building the
|
||||
/// nodes for a given statement.
|
||||
StmtNodeBuilder* Builder;
|
||||
|
||||
/// StateMgr - Object that manages the data for all created states.
|
||||
GRStateManager StateMgr;
|
||||
|
||||
/// BugTypes - Objects used for reporting bugs.
|
||||
typedef std::vector<BugType*> BugTypeSet;
|
||||
BugTypeSet BugTypes;
|
||||
|
||||
/// SymMgr - Object that manages the symbol information.
|
||||
SymbolManager& SymMgr;
|
||||
|
||||
/// EntryNode - The immediate predecessor node.
|
||||
NodeTy* EntryNode;
|
||||
|
||||
/// CleanedState - The state for EntryNode "cleaned" of all dead
|
||||
/// variables and symbols (as determined by a liveness analysis).
|
||||
const GRState* CleanedState;
|
||||
|
||||
/// CurrentStmt - The current block-level statement.
|
||||
Stmt* CurrentStmt;
|
||||
|
||||
// Obj-C Class Identifiers.
|
||||
IdentifierInfo* NSExceptionII;
|
||||
|
||||
// Obj-C Selectors.
|
||||
Selector* NSExceptionInstanceRaiseSelectors;
|
||||
Selector RaiseSel;
|
||||
|
||||
llvm::OwningPtr<GRSimpleAPICheck> BatchAuditor;
|
||||
|
||||
/// PurgeDead - Remove dead bindings before processing a statement.
|
||||
bool PurgeDead;
|
||||
|
||||
public:
|
||||
typedef llvm::SmallPtrSet<NodeTy*,2> ErrorNodes;
|
||||
typedef llvm::DenseMap<NodeTy*, Expr*> UndefArgsTy;
|
||||
|
||||
/// RetsStackAddr - Nodes in the ExplodedGraph that result from returning
|
||||
/// the address of a stack variable.
|
||||
ErrorNodes RetsStackAddr;
|
||||
|
||||
/// RetsUndef - Nodes in the ExplodedGraph that result from returning
|
||||
/// an undefined value.
|
||||
ErrorNodes RetsUndef;
|
||||
|
||||
/// UndefBranches - Nodes in the ExplodedGraph that result from
|
||||
/// taking a branch based on an undefined value.
|
||||
ErrorNodes UndefBranches;
|
||||
|
||||
/// UndefStores - Sinks in the ExplodedGraph that result from
|
||||
/// making a store to an undefined lvalue.
|
||||
ErrorNodes UndefStores;
|
||||
|
||||
/// NoReturnCalls - Sinks in the ExplodedGraph that result from
|
||||
// calling a function with the attribute "noreturn".
|
||||
ErrorNodes NoReturnCalls;
|
||||
|
||||
/// ImplicitNullDeref - Nodes in the ExplodedGraph that result from
|
||||
/// taking a dereference on a symbolic pointer that MAY be NULL.
|
||||
ErrorNodes ImplicitNullDeref;
|
||||
|
||||
/// ExplicitNullDeref - Nodes in the ExplodedGraph that result from
|
||||
/// taking a dereference on a symbolic pointer that MUST be NULL.
|
||||
ErrorNodes ExplicitNullDeref;
|
||||
|
||||
/// UnitDeref - Nodes in the ExplodedGraph that result from
|
||||
/// taking a dereference on an undefined value.
|
||||
ErrorNodes UndefDeref;
|
||||
|
||||
/// ImplicitBadDivides - Nodes in the ExplodedGraph that result from
|
||||
/// evaluating a divide or modulo operation where the denominator
|
||||
/// MAY be zero.
|
||||
ErrorNodes ImplicitBadDivides;
|
||||
|
||||
/// ExplicitBadDivides - Nodes in the ExplodedGraph that result from
|
||||
/// evaluating a divide or modulo operation where the denominator
|
||||
/// MUST be zero or undefined.
|
||||
ErrorNodes ExplicitBadDivides;
|
||||
|
||||
/// ImplicitBadSizedVLA - Nodes in the ExplodedGraph that result from
|
||||
/// constructing a zero-sized VLA where the size may be zero.
|
||||
ErrorNodes ImplicitBadSizedVLA;
|
||||
|
||||
/// ExplicitBadSizedVLA - Nodes in the ExplodedGraph that result from
|
||||
/// constructing a zero-sized VLA where the size must be zero.
|
||||
ErrorNodes ExplicitBadSizedVLA;
|
||||
|
||||
/// UndefResults - Nodes in the ExplodedGraph where the operands are defined
|
||||
/// by the result is not. Excludes divide-by-zero errors.
|
||||
ErrorNodes UndefResults;
|
||||
|
||||
/// BadCalls - Nodes in the ExplodedGraph resulting from calls to function
|
||||
/// pointers that are NULL (or other constants) or Undefined.
|
||||
ErrorNodes BadCalls;
|
||||
|
||||
/// UndefReceiver - Nodes in the ExplodedGraph resulting from message
|
||||
/// ObjC message expressions where the receiver is undefined (uninitialized).
|
||||
ErrorNodes UndefReceivers;
|
||||
|
||||
/// UndefArg - Nodes in the ExplodedGraph resulting from calls to functions
|
||||
/// where a pass-by-value argument has an undefined value.
|
||||
UndefArgsTy UndefArgs;
|
||||
|
||||
/// MsgExprUndefArgs - Nodes in the ExplodedGraph resulting from
|
||||
/// message expressions where a pass-by-value argument has an undefined
|
||||
/// value.
|
||||
UndefArgsTy MsgExprUndefArgs;
|
||||
|
||||
/// OutOfBoundMemAccesses - Nodes in the ExplodedGraph resulting from
|
||||
/// out-of-bound memory accesses where the index MAY be out-of-bound.
|
||||
ErrorNodes ImplicitOOBMemAccesses;
|
||||
|
||||
/// OutOfBoundMemAccesses - Nodes in the ExplodedGraph resulting from
|
||||
/// out-of-bound memory accesses where the index MUST be out-of-bound.
|
||||
ErrorNodes ExplicitOOBMemAccesses;
|
||||
|
||||
public:
|
||||
GRExprEngine(CFG& cfg, Decl& CD, ASTContext& Ctx, LiveVariables& L,
|
||||
bool purgeDead,
|
||||
StoreManagerCreator SMC = CreateBasicStoreManager,
|
||||
ConstraintManagerCreator CMC = CreateBasicConstraintManager);
|
||||
|
||||
~GRExprEngine();
|
||||
|
||||
void ExecuteWorkList(unsigned Steps = 150000) {
|
||||
CoreEngine.ExecuteWorkList(Steps);
|
||||
}
|
||||
|
||||
/// getContext - Return the ASTContext associated with this analysis.
|
||||
ASTContext& getContext() const { return G.getContext(); }
|
||||
|
||||
/// getCFG - Returns the CFG associated with this analysis.
|
||||
CFG& getCFG() { return G.getCFG(); }
|
||||
|
||||
GRTransferFuncs& getTF() { return *StateMgr.TF; }
|
||||
|
||||
/// setTransferFunctions
|
||||
void setTransferFunctions(GRTransferFuncs* tf);
|
||||
|
||||
void setTransferFunctions(GRTransferFuncs& tf) {
|
||||
setTransferFunctions(&tf);
|
||||
}
|
||||
|
||||
/// ViewGraph - Visualize the ExplodedGraph created by executing the
|
||||
/// simulation.
|
||||
void ViewGraph(bool trim = false);
|
||||
|
||||
void ViewGraph(NodeTy** Beg, NodeTy** End);
|
||||
|
||||
/// getLiveness - Returned computed live-variables information for the
|
||||
/// analyzed function.
|
||||
const LiveVariables& getLiveness() const { return Liveness; }
|
||||
LiveVariables& getLiveness() { return Liveness; }
|
||||
|
||||
/// getInitialState - Return the initial state used for the root vertex
|
||||
/// in the ExplodedGraph.
|
||||
const GRState* getInitialState();
|
||||
|
||||
GraphTy& getGraph() { return G; }
|
||||
const GraphTy& getGraph() const { return G; }
|
||||
|
||||
typedef BugTypeSet::iterator bug_type_iterator;
|
||||
typedef BugTypeSet::const_iterator const_bug_type_iterator;
|
||||
|
||||
bug_type_iterator bug_types_begin() { return BugTypes.begin(); }
|
||||
bug_type_iterator bug_types_end() { return BugTypes.end(); }
|
||||
|
||||
const_bug_type_iterator bug_types_begin() const { return BugTypes.begin(); }
|
||||
const_bug_type_iterator bug_types_end() const { return BugTypes.end(); }
|
||||
|
||||
/// Register - Register a BugType with the analyzer engine. A registered
|
||||
/// BugType object will have its 'EmitWarnings' method called when the
|
||||
/// the analyzer finishes analyzing a method or function.
|
||||
void Register(BugType* B) {
|
||||
BugTypes.push_back(B);
|
||||
}
|
||||
|
||||
void RegisterInternalChecks();
|
||||
|
||||
void EmitWarnings(BugReporterData& BRData);
|
||||
|
||||
bool isRetStackAddr(const NodeTy* N) const {
|
||||
return N->isSink() && RetsStackAddr.count(const_cast<NodeTy*>(N)) != 0;
|
||||
}
|
||||
|
||||
bool isUndefControlFlow(const NodeTy* N) const {
|
||||
return N->isSink() && UndefBranches.count(const_cast<NodeTy*>(N)) != 0;
|
||||
}
|
||||
|
||||
bool isUndefStore(const NodeTy* N) const {
|
||||
return N->isSink() && UndefStores.count(const_cast<NodeTy*>(N)) != 0;
|
||||
}
|
||||
|
||||
bool isImplicitNullDeref(const NodeTy* N) const {
|
||||
return N->isSink() && ImplicitNullDeref.count(const_cast<NodeTy*>(N)) != 0;
|
||||
}
|
||||
|
||||
bool isExplicitNullDeref(const NodeTy* N) const {
|
||||
return N->isSink() && ExplicitNullDeref.count(const_cast<NodeTy*>(N)) != 0;
|
||||
}
|
||||
|
||||
bool isUndefDeref(const NodeTy* N) const {
|
||||
return N->isSink() && UndefDeref.count(const_cast<NodeTy*>(N)) != 0;
|
||||
}
|
||||
|
||||
bool isImplicitBadDivide(const NodeTy* N) const {
|
||||
return N->isSink() && ImplicitBadDivides.count(const_cast<NodeTy*>(N)) != 0;
|
||||
}
|
||||
|
||||
bool isExplicitBadDivide(const NodeTy* N) const {
|
||||
return N->isSink() && ExplicitBadDivides.count(const_cast<NodeTy*>(N)) != 0;
|
||||
}
|
||||
|
||||
bool isNoReturnCall(const NodeTy* N) const {
|
||||
return N->isSink() && NoReturnCalls.count(const_cast<NodeTy*>(N)) != 0;
|
||||
}
|
||||
|
||||
bool isUndefResult(const NodeTy* N) const {
|
||||
return N->isSink() && UndefResults.count(const_cast<NodeTy*>(N)) != 0;
|
||||
}
|
||||
|
||||
bool isBadCall(const NodeTy* N) const {
|
||||
return N->isSink() && BadCalls.count(const_cast<NodeTy*>(N)) != 0;
|
||||
}
|
||||
|
||||
bool isUndefArg(const NodeTy* N) const {
|
||||
return N->isSink() &&
|
||||
(UndefArgs.find(const_cast<NodeTy*>(N)) != UndefArgs.end() ||
|
||||
MsgExprUndefArgs.find(const_cast<NodeTy*>(N)) != MsgExprUndefArgs.end());
|
||||
}
|
||||
|
||||
bool isUndefReceiver(const NodeTy* N) const {
|
||||
return N->isSink() && UndefReceivers.count(const_cast<NodeTy*>(N)) != 0;
|
||||
}
|
||||
|
||||
typedef ErrorNodes::iterator ret_stackaddr_iterator;
|
||||
ret_stackaddr_iterator ret_stackaddr_begin() { return RetsStackAddr.begin(); }
|
||||
ret_stackaddr_iterator ret_stackaddr_end() { return RetsStackAddr.end(); }
|
||||
|
||||
typedef ErrorNodes::iterator ret_undef_iterator;
|
||||
ret_undef_iterator ret_undef_begin() { return RetsUndef.begin(); }
|
||||
ret_undef_iterator ret_undef_end() { return RetsUndef.end(); }
|
||||
|
||||
typedef ErrorNodes::iterator undef_branch_iterator;
|
||||
undef_branch_iterator undef_branches_begin() { return UndefBranches.begin(); }
|
||||
undef_branch_iterator undef_branches_end() { return UndefBranches.end(); }
|
||||
|
||||
typedef ErrorNodes::iterator null_deref_iterator;
|
||||
null_deref_iterator null_derefs_begin() { return ExplicitNullDeref.begin(); }
|
||||
null_deref_iterator null_derefs_end() { return ExplicitNullDeref.end(); }
|
||||
|
||||
null_deref_iterator implicit_null_derefs_begin() {
|
||||
return ImplicitNullDeref.begin();
|
||||
}
|
||||
null_deref_iterator implicit_null_derefs_end() {
|
||||
return ImplicitNullDeref.end();
|
||||
}
|
||||
|
||||
typedef ErrorNodes::iterator undef_deref_iterator;
|
||||
undef_deref_iterator undef_derefs_begin() { return UndefDeref.begin(); }
|
||||
undef_deref_iterator undef_derefs_end() { return UndefDeref.end(); }
|
||||
|
||||
typedef ErrorNodes::iterator bad_divide_iterator;
|
||||
|
||||
bad_divide_iterator explicit_bad_divides_begin() {
|
||||
return ExplicitBadDivides.begin();
|
||||
}
|
||||
|
||||
bad_divide_iterator explicit_bad_divides_end() {
|
||||
return ExplicitBadDivides.end();
|
||||
}
|
||||
|
||||
bad_divide_iterator implicit_bad_divides_begin() {
|
||||
return ImplicitBadDivides.begin();
|
||||
}
|
||||
|
||||
bad_divide_iterator implicit_bad_divides_end() {
|
||||
return ImplicitBadDivides.end();
|
||||
}
|
||||
|
||||
typedef ErrorNodes::iterator undef_result_iterator;
|
||||
undef_result_iterator undef_results_begin() { return UndefResults.begin(); }
|
||||
undef_result_iterator undef_results_end() { return UndefResults.end(); }
|
||||
|
||||
typedef ErrorNodes::iterator bad_calls_iterator;
|
||||
bad_calls_iterator bad_calls_begin() { return BadCalls.begin(); }
|
||||
bad_calls_iterator bad_calls_end() { return BadCalls.end(); }
|
||||
|
||||
typedef UndefArgsTy::iterator undef_arg_iterator;
|
||||
undef_arg_iterator undef_arg_begin() { return UndefArgs.begin(); }
|
||||
undef_arg_iterator undef_arg_end() { return UndefArgs.end(); }
|
||||
|
||||
undef_arg_iterator msg_expr_undef_arg_begin() {
|
||||
return MsgExprUndefArgs.begin();
|
||||
}
|
||||
undef_arg_iterator msg_expr_undef_arg_end() {
|
||||
return MsgExprUndefArgs.end();
|
||||
}
|
||||
|
||||
typedef ErrorNodes::iterator undef_receivers_iterator;
|
||||
|
||||
undef_receivers_iterator undef_receivers_begin() {
|
||||
return UndefReceivers.begin();
|
||||
}
|
||||
|
||||
undef_receivers_iterator undef_receivers_end() {
|
||||
return UndefReceivers.end();
|
||||
}
|
||||
|
||||
typedef ErrorNodes::iterator oob_memacc_iterator;
|
||||
oob_memacc_iterator implicit_oob_memacc_begin() {
|
||||
return ImplicitOOBMemAccesses.begin();
|
||||
}
|
||||
oob_memacc_iterator implicit_oob_memacc_end() {
|
||||
return ImplicitOOBMemAccesses.end();
|
||||
}
|
||||
oob_memacc_iterator explicit_oob_memacc_begin() {
|
||||
return ExplicitOOBMemAccesses.begin();
|
||||
}
|
||||
oob_memacc_iterator explicit_oob_memacc_end() {
|
||||
return ExplicitOOBMemAccesses.end();
|
||||
}
|
||||
|
||||
void AddCheck(GRSimpleAPICheck* A, Stmt::StmtClass C);
|
||||
|
||||
/// ProcessStmt - Called by GRCoreEngine. Used to generate new successor
|
||||
/// nodes by processing the 'effects' of a block-level statement.
|
||||
void ProcessStmt(Stmt* S, StmtNodeBuilder& builder);
|
||||
|
||||
/// ProcessBlockEntrance - Called by GRCoreEngine when start processing
|
||||
/// a CFGBlock. This method returns true if the analysis should continue
|
||||
/// exploring the given path, and false otherwise.
|
||||
bool ProcessBlockEntrance(CFGBlock* B, const GRState* St,
|
||||
GRBlockCounter BC);
|
||||
|
||||
/// ProcessBranch - Called by GRCoreEngine. Used to generate successor
|
||||
/// nodes by processing the 'effects' of a branch condition.
|
||||
void ProcessBranch(Stmt* Condition, Stmt* Term, BranchNodeBuilder& builder);
|
||||
|
||||
/// ProcessIndirectGoto - Called by GRCoreEngine. Used to generate successor
|
||||
/// nodes by processing the 'effects' of a computed goto jump.
|
||||
void ProcessIndirectGoto(IndirectGotoNodeBuilder& builder);
|
||||
|
||||
/// ProcessSwitch - Called by GRCoreEngine. Used to generate successor
|
||||
/// nodes by processing the 'effects' of a switch statement.
|
||||
void ProcessSwitch(SwitchNodeBuilder& builder);
|
||||
|
||||
/// ProcessEndPath - Called by GRCoreEngine. Used to generate end-of-path
|
||||
/// nodes when the control reaches the end of a function.
|
||||
void ProcessEndPath(EndPathNodeBuilder& builder) {
|
||||
getTF().EvalEndPath(*this, builder);
|
||||
StateMgr.EndPath(builder.getState());
|
||||
}
|
||||
|
||||
GRStateManager& getStateManager() { return StateMgr; }
|
||||
const GRStateManager& getStateManger() const { return StateMgr; }
|
||||
|
||||
StoreManager& getStoreManager() { return StateMgr.getStoreManager(); }
|
||||
|
||||
BasicValueFactory& getBasicVals() {
|
||||
return StateMgr.getBasicVals();
|
||||
}
|
||||
const BasicValueFactory& getBasicVals() const {
|
||||
return StateMgr.getBasicVals();
|
||||
}
|
||||
|
||||
SymbolManager& getSymbolManager() { return SymMgr; }
|
||||
const SymbolManager& getSymbolManager() const { return SymMgr; }
|
||||
|
||||
protected:
|
||||
|
||||
const GRState* GetState(NodeTy* N) {
|
||||
return N == EntryNode ? CleanedState : N->getState();
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
const GRState* BindExpr(const GRState* St, Expr* Ex, SVal V) {
|
||||
return StateMgr.BindExpr(St, Ex, V);
|
||||
}
|
||||
|
||||
const GRState* BindExpr(const GRState* St, const Expr* Ex, SVal V) {
|
||||
return BindExpr(St, const_cast<Expr*>(Ex), V);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
const GRState* BindBlkExpr(const GRState* St, Expr* Ex, SVal V) {
|
||||
return StateMgr.BindExpr(St, Ex, V, true, false);
|
||||
}
|
||||
|
||||
const GRState* BindLoc(const GRState* St, Loc LV, SVal V) {
|
||||
return StateMgr.BindLoc(St, LV, V);
|
||||
}
|
||||
|
||||
SVal GetSVal(const GRState* St, Stmt* Ex) {
|
||||
return StateMgr.GetSVal(St, Ex);
|
||||
}
|
||||
|
||||
SVal GetSVal(const GRState* St, const Stmt* Ex) {
|
||||
return GetSVal(St, const_cast<Stmt*>(Ex));
|
||||
}
|
||||
|
||||
SVal GetBlkExprSVal(const GRState* St, Stmt* Ex) {
|
||||
return StateMgr.GetBlkExprSVal(St, Ex);
|
||||
}
|
||||
|
||||
SVal GetSVal(const GRState* St, Loc LV, QualType T = QualType()) {
|
||||
return StateMgr.GetSVal(St, LV, T);
|
||||
}
|
||||
|
||||
inline NonLoc MakeConstantVal(uint64_t X, Expr* Ex) {
|
||||
return NonLoc::MakeVal(getBasicVals(), X, Ex->getType());
|
||||
}
|
||||
|
||||
/// Assume - Create new state by assuming that a given expression
|
||||
/// is true or false.
|
||||
const GRState* Assume(const GRState* St, SVal Cond, bool Assumption,
|
||||
bool& isFeasible) {
|
||||
return StateMgr.Assume(St, Cond, Assumption, isFeasible);
|
||||
}
|
||||
|
||||
const GRState* Assume(const GRState* St, Loc Cond, bool Assumption,
|
||||
bool& isFeasible) {
|
||||
return StateMgr.Assume(St, Cond, Assumption, isFeasible);
|
||||
}
|
||||
|
||||
const GRState* AssumeInBound(const GRState* St, SVal Idx, SVal UpperBound,
|
||||
bool Assumption, bool& isFeasible) {
|
||||
return StateMgr.AssumeInBound(St, Idx, UpperBound, Assumption, isFeasible);
|
||||
}
|
||||
|
||||
NodeTy* MakeNode(NodeSet& Dst, Stmt* S, NodeTy* Pred, const GRState* St,
|
||||
ProgramPoint::Kind K = ProgramPoint::PostStmtKind) {
|
||||
assert (Builder && "GRStmtNodeBuilder not present.");
|
||||
return Builder->MakeNode(Dst, S, Pred, St, K);
|
||||
}
|
||||
|
||||
/// Visit - Transfer function logic for all statements. Dispatches to
|
||||
/// other functions that handle specific kinds of statements.
|
||||
void Visit(Stmt* S, NodeTy* Pred, NodeSet& Dst);
|
||||
|
||||
/// VisitLValue - Evaluate the lvalue of the expression. For example, if Ex is
|
||||
/// a DeclRefExpr, it evaluates to the MemRegionVal which represents its
|
||||
/// storage location. Note that not all kinds of expressions has lvalue.
|
||||
void VisitLValue(Expr* Ex, NodeTy* Pred, NodeSet& Dst);
|
||||
|
||||
/// VisitArraySubscriptExpr - Transfer function for array accesses.
|
||||
void VisitArraySubscriptExpr(ArraySubscriptExpr* Ex, NodeTy* Pred,
|
||||
NodeSet& Dst, bool asLValue);
|
||||
|
||||
/// VisitAsmStmt - Transfer function logic for inline asm.
|
||||
void VisitAsmStmt(AsmStmt* A, NodeTy* Pred, NodeSet& Dst);
|
||||
|
||||
void VisitAsmStmtHelperOutputs(AsmStmt* A,
|
||||
AsmStmt::outputs_iterator I,
|
||||
AsmStmt::outputs_iterator E,
|
||||
NodeTy* Pred, NodeSet& Dst);
|
||||
|
||||
void VisitAsmStmtHelperInputs(AsmStmt* A,
|
||||
AsmStmt::inputs_iterator I,
|
||||
AsmStmt::inputs_iterator E,
|
||||
NodeTy* Pred, NodeSet& Dst);
|
||||
|
||||
/// VisitBinaryOperator - Transfer function logic for binary operators.
|
||||
void VisitBinaryOperator(BinaryOperator* B, NodeTy* Pred, NodeSet& Dst);
|
||||
|
||||
|
||||
/// VisitCall - Transfer function for function calls.
|
||||
void VisitCall(CallExpr* CE, NodeTy* Pred,
|
||||
CallExpr::arg_iterator AI, CallExpr::arg_iterator AE,
|
||||
NodeSet& Dst);
|
||||
void VisitCallRec(CallExpr* CE, NodeTy* Pred,
|
||||
CallExpr::arg_iterator AI, CallExpr::arg_iterator AE,
|
||||
NodeSet& Dst, const FunctionTypeProto *,
|
||||
unsigned ParamIdx = 0);
|
||||
|
||||
/// VisitCast - Transfer function logic for all casts (implicit and explicit).
|
||||
void VisitCast(Expr* CastE, Expr* Ex, NodeTy* Pred, NodeSet& Dst);
|
||||
|
||||
/// VisitCastPointerToInteger - Transfer function (called by VisitCast) that
|
||||
/// handles pointer to integer casts and array to integer casts.
|
||||
void VisitCastPointerToInteger(SVal V, const GRState* state, QualType PtrTy,
|
||||
Expr* CastE, NodeTy* Pred, NodeSet& Dst);
|
||||
|
||||
/// VisitCompoundLiteralExpr - Transfer function logic for compound literals.
|
||||
void VisitCompoundLiteralExpr(CompoundLiteralExpr* CL, NodeTy* Pred,
|
||||
NodeSet& Dst, bool asLValue);
|
||||
|
||||
/// VisitDeclRefExpr - Transfer function logic for DeclRefExprs.
|
||||
void VisitDeclRefExpr(DeclRefExpr* DR, NodeTy* Pred, NodeSet& Dst,
|
||||
bool asLValue);
|
||||
|
||||
/// VisitDeclStmt - Transfer function logic for DeclStmts.
|
||||
void VisitDeclStmt(DeclStmt* DS, NodeTy* Pred, NodeSet& Dst);
|
||||
|
||||
/// VisitGuardedExpr - Transfer function logic for ?, __builtin_choose
|
||||
void VisitGuardedExpr(Expr* Ex, Expr* L, Expr* R, NodeTy* Pred, NodeSet& Dst);
|
||||
|
||||
void VisitInitListExpr(InitListExpr* E, NodeTy* Pred, NodeSet& Dst);
|
||||
|
||||
/// VisitLogicalExpr - Transfer function logic for '&&', '||'
|
||||
void VisitLogicalExpr(BinaryOperator* B, NodeTy* Pred, NodeSet& Dst);
|
||||
|
||||
/// VisitMemberExpr - Transfer function for member expressions.
|
||||
void VisitMemberExpr(MemberExpr* M, NodeTy* Pred, NodeSet& Dst,bool asLValue);
|
||||
|
||||
/// VisitObjCIvarRefExpr - Transfer function logic for ObjCIvarRefExprs.
|
||||
void VisitObjCIvarRefExpr(ObjCIvarRefExpr* DR, NodeTy* Pred, NodeSet& Dst,
|
||||
bool asLValue);
|
||||
|
||||
/// VisitObjCForCollectionStmt - Transfer function logic for
|
||||
/// ObjCForCollectionStmt.
|
||||
void VisitObjCForCollectionStmt(ObjCForCollectionStmt* S, NodeTy* Pred,
|
||||
NodeSet& Dst);
|
||||
|
||||
void VisitObjCForCollectionStmtAux(ObjCForCollectionStmt* S, NodeTy* Pred,
|
||||
NodeSet& Dst, SVal ElementV);
|
||||
|
||||
/// VisitObjCMessageExpr - Transfer function for ObjC message expressions.
|
||||
void VisitObjCMessageExpr(ObjCMessageExpr* ME, NodeTy* Pred, NodeSet& Dst);
|
||||
|
||||
void VisitObjCMessageExprArgHelper(ObjCMessageExpr* ME,
|
||||
ObjCMessageExpr::arg_iterator I,
|
||||
ObjCMessageExpr::arg_iterator E,
|
||||
NodeTy* Pred, NodeSet& Dst);
|
||||
|
||||
void VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME, NodeTy* Pred,
|
||||
NodeSet& Dst);
|
||||
|
||||
/// VisitReturnStmt - Transfer function logic for return statements.
|
||||
void VisitReturnStmt(ReturnStmt* R, NodeTy* Pred, NodeSet& Dst);
|
||||
|
||||
/// VisitSizeOfAlignOfExpr - Transfer function for sizeof.
|
||||
void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr* Ex, NodeTy* Pred,
|
||||
NodeSet& Dst);
|
||||
|
||||
/// VisitUnaryOperator - Transfer function logic for unary operators.
|
||||
void VisitUnaryOperator(UnaryOperator* B, NodeTy* Pred, NodeSet& Dst,
|
||||
bool asLValue);
|
||||
|
||||
const GRState* CheckDivideZero(Expr* Ex, const GRState* St, NodeTy* Pred,
|
||||
SVal Denom);
|
||||
|
||||
SVal EvalCast(SVal X, QualType CastT) {
|
||||
if (X.isUnknownOrUndef())
|
||||
return X;
|
||||
|
||||
if (isa<Loc>(X))
|
||||
return getTF().EvalCast(*this, cast<Loc>(X), CastT);
|
||||
else
|
||||
return getTF().EvalCast(*this, cast<NonLoc>(X), CastT);
|
||||
}
|
||||
|
||||
SVal EvalMinus(UnaryOperator* U, SVal X) {
|
||||
return X.isValid() ? getTF().EvalMinus(*this, U, cast<NonLoc>(X)) : X;
|
||||
}
|
||||
|
||||
SVal EvalComplement(SVal X) {
|
||||
return X.isValid() ? getTF().EvalComplement(*this, cast<NonLoc>(X)) : X;
|
||||
}
|
||||
|
||||
SVal EvalBinOp(BinaryOperator::Opcode Op, NonLoc L, NonLoc R) {
|
||||
return R.isValid() ? getTF().DetermEvalBinOpNN(*this, Op, L, R)
|
||||
: R;
|
||||
}
|
||||
|
||||
SVal EvalBinOp(BinaryOperator::Opcode Op, NonLoc L, SVal R) {
|
||||
return R.isValid() ? getTF().DetermEvalBinOpNN(*this, Op, L,
|
||||
cast<NonLoc>(R)) : R;
|
||||
}
|
||||
|
||||
void EvalBinOp(ExplodedNodeSet<GRState>& Dst, Expr* Ex,
|
||||
BinaryOperator::Opcode Op, NonLoc L, NonLoc R,
|
||||
ExplodedNode<GRState>* Pred);
|
||||
|
||||
void EvalBinOp(GRStateSet& OStates, const GRState* St, Expr* Ex,
|
||||
BinaryOperator::Opcode Op, NonLoc L, NonLoc R);
|
||||
|
||||
SVal EvalBinOp(BinaryOperator::Opcode Op, SVal L, SVal R);
|
||||
|
||||
void EvalCall(NodeSet& Dst, CallExpr* CE, SVal L, NodeTy* Pred) {
|
||||
assert (Builder && "GRStmtNodeBuilder must be defined.");
|
||||
getTF().EvalCall(Dst, *this, *Builder, CE, L, Pred);
|
||||
}
|
||||
|
||||
void EvalObjCMessageExpr(NodeSet& Dst, ObjCMessageExpr* ME, NodeTy* Pred) {
|
||||
assert (Builder && "GRStmtNodeBuilder must be defined.");
|
||||
getTF().EvalObjCMessageExpr(Dst, *this, *Builder, ME, Pred);
|
||||
}
|
||||
|
||||
void EvalStore(NodeSet& Dst, Expr* E, NodeTy* Pred, const GRState* St,
|
||||
SVal TargetLV, SVal Val);
|
||||
|
||||
void EvalStore(NodeSet& Dst, Expr* E, Expr* StoreE, NodeTy* Pred,
|
||||
const GRState* St, SVal TargetLV, SVal Val);
|
||||
|
||||
// FIXME: The "CheckOnly" option exists only because Array and Field
|
||||
// loads aren't fully implemented. Eventually this option will go away.
|
||||
|
||||
void EvalLoad(NodeSet& Dst, Expr* Ex, NodeTy* Pred,
|
||||
const GRState* St, SVal location, bool CheckOnly = false);
|
||||
|
||||
NodeTy* EvalLocation(Stmt* Ex, NodeTy* Pred,
|
||||
const GRState* St, SVal location);
|
||||
|
||||
void EvalReturn(NodeSet& Dst, ReturnStmt* s, NodeTy* Pred);
|
||||
|
||||
const GRState* MarkBranch(const GRState* St, Stmt* Terminator,
|
||||
bool branchTaken);
|
||||
};
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
#endif
|
||||
@@ -1,41 +0,0 @@
|
||||
// GRCheckAPI.h - Simple API checks based on GRAuditor ------------*- C++ -*--//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the interface for building simple, path-sensitive checks
|
||||
// that are stateless and only emit warnings at errors that occur at
|
||||
// CallExpr or ObjCMessageExpr.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSIS_GRAPICHECKS
|
||||
#define LLVM_CLANG_ANALYSIS_GRAPICHECKS
|
||||
|
||||
#include "clang/Analysis/PathSensitive/GRAuditor.h"
|
||||
#include "clang/Analysis/PathSensitive/GRState.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
class Diagnostic;
|
||||
class BugReporter;
|
||||
class ASTContext;
|
||||
class GRExprEngine;
|
||||
class PathDiagnosticClient;
|
||||
template <typename T> class ExplodedGraph;
|
||||
|
||||
|
||||
class GRSimpleAPICheck : public GRAuditor<GRState> {
|
||||
public:
|
||||
GRSimpleAPICheck() {}
|
||||
virtual ~GRSimpleAPICheck() {}
|
||||
virtual void EmitWarnings(BugReporter& BR) = 0;
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
@@ -1,746 +0,0 @@
|
||||
//== GRState*h - Path-Sens. "State" for tracking valuues -----*- 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 SymbolRef, ExprBindKey, and GRState*
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSIS_VALUESTATE_H
|
||||
#define LLVM_CLANG_ANALYSIS_VALUESTATE_H
|
||||
|
||||
// FIXME: Reduce the number of includes.
|
||||
|
||||
#include "clang/Analysis/PathSensitive/Environment.h"
|
||||
#include "clang/Analysis/PathSensitive/Store.h"
|
||||
#include "clang/Analysis/PathSensitive/ConstraintManager.h"
|
||||
#include "clang/Analysis/PathSensitive/MemRegion.h"
|
||||
#include "clang/Analysis/PathSensitive/SVals.h"
|
||||
#include "clang/Analysis/PathSensitive/BasicValueFactory.h"
|
||||
#include "clang/Analysis/PathSensitive/GRCoreEngine.h"
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/Analysis/Analyses/LiveVariables.h"
|
||||
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include "llvm/ADT/APSInt.h"
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
#include "llvm/ADT/ImmutableMap.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/DenseSet.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/Streams.h"
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace clang {
|
||||
|
||||
class GRStateManager;
|
||||
class GRTransferFuncs;
|
||||
|
||||
typedef ConstraintManager* (*ConstraintManagerCreator)(GRStateManager&);
|
||||
typedef StoreManager* (*StoreManagerCreator)(GRStateManager&);
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// GRStateTrait - Traits used by the Generic Data Map of a GRState.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
template <typename T> struct GRStatePartialTrait;
|
||||
|
||||
template <typename T> struct GRStateTrait {
|
||||
typedef typename T::data_type data_type;
|
||||
static inline void* GDMIndex() { return &T::TagInt; }
|
||||
static inline void* MakeVoidPtr(data_type D) { return (void*) D; }
|
||||
static inline data_type MakeData(void* const* P) {
|
||||
return P ? (data_type) *P : (data_type) 0;
|
||||
}
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// GRState- An ImmutableMap type Stmt*/Decl*/Symbols to SVals.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// GRState - This class encapsulates the actual data values for
|
||||
/// for a "state" in our symbolic value tracking. It is intended to be
|
||||
/// used as a functional object; that is once it is created and made
|
||||
/// "persistent" in a FoldingSet its values will never change.
|
||||
class GRState : public llvm::FoldingSetNode {
|
||||
public:
|
||||
// Typedefs.
|
||||
typedef llvm::ImmutableSet<llvm::APSInt*> IntSetTy;
|
||||
typedef llvm::ImmutableMap<void*, void*> GenericDataMap;
|
||||
|
||||
typedef GRStateManager ManagerTy;
|
||||
|
||||
private:
|
||||
void operator=(const GRState& R) const;
|
||||
|
||||
friend class GRStateManager;
|
||||
|
||||
Environment Env;
|
||||
Store St;
|
||||
|
||||
// FIXME: Make these private.
|
||||
public:
|
||||
GenericDataMap GDM;
|
||||
|
||||
public:
|
||||
|
||||
/// This ctor is used when creating the first GRState object.
|
||||
GRState(const Environment& env, Store st, GenericDataMap gdm)
|
||||
: Env(env),
|
||||
St(st),
|
||||
GDM(gdm) {}
|
||||
|
||||
/// Copy ctor - We must explicitly define this or else the "Next" ptr
|
||||
/// in FoldingSetNode will also get copied.
|
||||
GRState(const GRState& RHS)
|
||||
: llvm::FoldingSetNode(),
|
||||
Env(RHS.Env),
|
||||
St(RHS.St),
|
||||
GDM(RHS.GDM) {}
|
||||
|
||||
/// getEnvironment - Return the environment associated with this state.
|
||||
/// The environment is the mapping from expressions to values.
|
||||
const Environment& getEnvironment() const { return Env; }
|
||||
|
||||
/// getStore - Return the store associated with this state. The store
|
||||
/// is a mapping from locations to values.
|
||||
Store getStore() const { return St; }
|
||||
|
||||
/// getGDM - Return the generic data map associated with this state.
|
||||
GenericDataMap getGDM() const { return GDM; }
|
||||
|
||||
/// Profile - Profile the contents of a GRState object for use
|
||||
/// in a FoldingSet.
|
||||
static void Profile(llvm::FoldingSetNodeID& ID, const GRState* V) {
|
||||
V->Env.Profile(ID);
|
||||
ID.AddPointer(V->St);
|
||||
V->GDM.Profile(ID);
|
||||
}
|
||||
|
||||
/// Profile - Used to profile the contents of this object for inclusion
|
||||
/// in a FoldingSet.
|
||||
void Profile(llvm::FoldingSetNodeID& ID) const {
|
||||
Profile(ID, this);
|
||||
}
|
||||
|
||||
SVal LookupExpr(Expr* E) const {
|
||||
return Env.LookupExpr(E);
|
||||
}
|
||||
|
||||
// Iterators.
|
||||
typedef Environment::seb_iterator seb_iterator;
|
||||
seb_iterator seb_begin() const { return Env.seb_begin(); }
|
||||
seb_iterator seb_end() const { return Env.beb_end(); }
|
||||
|
||||
typedef Environment::beb_iterator beb_iterator;
|
||||
beb_iterator beb_begin() const { return Env.beb_begin(); }
|
||||
beb_iterator beb_end() const { return Env.beb_end(); }
|
||||
|
||||
// Trait based GDM dispatch.
|
||||
void* const* FindGDM(void* K) const;
|
||||
|
||||
template <typename T>
|
||||
typename GRStateTrait<T>::data_type
|
||||
get() const {
|
||||
return GRStateTrait<T>::MakeData(FindGDM(GRStateTrait<T>::GDMIndex()));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
typename GRStateTrait<T>::lookup_type
|
||||
get(typename GRStateTrait<T>::key_type key) const {
|
||||
void* const* d = FindGDM(GRStateTrait<T>::GDMIndex());
|
||||
return GRStateTrait<T>::Lookup(GRStateTrait<T>::MakeData(d), key);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool contains(typename GRStateTrait<T>::key_type key) const {
|
||||
void* const* d = FindGDM(GRStateTrait<T>::GDMIndex());
|
||||
return GRStateTrait<T>::Contains(GRStateTrait<T>::MakeData(d), key);
|
||||
}
|
||||
|
||||
// State pretty-printing.
|
||||
class Printer {
|
||||
public:
|
||||
virtual ~Printer() {}
|
||||
virtual void Print(std::ostream& Out, const GRState* state,
|
||||
const char* nl, const char* sep) = 0;
|
||||
};
|
||||
|
||||
void print(std::ostream& Out, StoreManager& StoreMgr,
|
||||
ConstraintManager& ConstraintMgr,
|
||||
Printer **Beg = 0, Printer **End = 0,
|
||||
const char* nl = "\n", const char *sep = "") const;
|
||||
|
||||
// Tags used for the Generic Data Map.
|
||||
struct NullDerefTag {
|
||||
static int TagInt;
|
||||
typedef const SVal* data_type;
|
||||
};
|
||||
};
|
||||
|
||||
template<> struct GRTrait<GRState*> {
|
||||
static inline void* toPtr(GRState* St) { return (void*) St; }
|
||||
static inline GRState* toState(void* P) { return (GRState*) P; }
|
||||
static inline void Profile(llvm::FoldingSetNodeID& profile, GRState* St) {
|
||||
// At this point states have already been uniqued. Just
|
||||
// add the pointer.
|
||||
profile.AddPointer(St);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class GRStateSet {
|
||||
typedef llvm::SmallPtrSet<const GRState*,5> ImplTy;
|
||||
ImplTy Impl;
|
||||
public:
|
||||
GRStateSet() {}
|
||||
|
||||
inline void Add(const GRState* St) {
|
||||
Impl.insert(St);
|
||||
}
|
||||
|
||||
typedef ImplTy::const_iterator iterator;
|
||||
|
||||
inline unsigned size() const { return Impl.size(); }
|
||||
inline bool empty() const { return Impl.empty(); }
|
||||
|
||||
inline iterator begin() const { return Impl.begin(); }
|
||||
inline iterator end() const { return Impl.end(); }
|
||||
|
||||
class AutoPopulate {
|
||||
GRStateSet& S;
|
||||
unsigned StartSize;
|
||||
const GRState* St;
|
||||
public:
|
||||
AutoPopulate(GRStateSet& s, const GRState* st)
|
||||
: S(s), StartSize(S.size()), St(st) {}
|
||||
|
||||
~AutoPopulate() {
|
||||
if (StartSize == S.size())
|
||||
S.Add(St);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// GRStateManager - Factory object for GRStates.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
class GRStateRef;
|
||||
|
||||
class GRStateManager {
|
||||
friend class GRExprEngine;
|
||||
friend class GRStateRef;
|
||||
|
||||
private:
|
||||
EnvironmentManager EnvMgr;
|
||||
llvm::OwningPtr<StoreManager> StoreMgr;
|
||||
llvm::OwningPtr<ConstraintManager> ConstraintMgr;
|
||||
GRState::IntSetTy::Factory ISetFactory;
|
||||
|
||||
GRState::GenericDataMap::Factory GDMFactory;
|
||||
|
||||
typedef llvm::DenseMap<void*,std::pair<void*,void (*)(void*)> > GDMContextsTy;
|
||||
GDMContextsTy GDMContexts;
|
||||
|
||||
/// Printers - A set of printer objects used for pretty-printing a GRState.
|
||||
/// GRStateManager owns these objects.
|
||||
std::vector<GRState::Printer*> Printers;
|
||||
|
||||
/// StateSet - FoldingSet containing all the states created for analyzing
|
||||
/// a particular function. This is used to unique states.
|
||||
llvm::FoldingSet<GRState> StateSet;
|
||||
|
||||
/// ValueMgr - Object that manages the data for all created SVals.
|
||||
BasicValueFactory BasicVals;
|
||||
|
||||
/// SymMgr - Object that manages the symbol information.
|
||||
SymbolManager SymMgr;
|
||||
|
||||
/// Alloc - A BumpPtrAllocator to allocate states.
|
||||
llvm::BumpPtrAllocator& Alloc;
|
||||
|
||||
/// CurrentStmt - The block-level statement currently being visited. This
|
||||
/// is set by GRExprEngine.
|
||||
Stmt* CurrentStmt;
|
||||
|
||||
/// cfg - The CFG for the analyzed function/method.
|
||||
CFG& cfg;
|
||||
|
||||
/// codedecl - The Decl representing the function/method being analyzed.
|
||||
const Decl& codedecl;
|
||||
|
||||
/// TF - Object that represents a bundle of transfer functions
|
||||
/// for manipulating and creating SVals.
|
||||
GRTransferFuncs* TF;
|
||||
|
||||
/// Liveness - live-variables information of the ValueDecl* and block-level
|
||||
/// Expr* in the CFG. Used to get initial store and prune out dead state.
|
||||
LiveVariables& Liveness;
|
||||
|
||||
private:
|
||||
|
||||
Environment RemoveBlkExpr(const Environment& Env, Expr* E) {
|
||||
return EnvMgr.RemoveBlkExpr(Env, E);
|
||||
}
|
||||
|
||||
// FIXME: Remove when we do lazy initializaton of variable bindings.
|
||||
// const GRState* BindVar(const GRState* St, VarDecl* D, SVal V) {
|
||||
// return SetSVal(St, getLoc(D), V);
|
||||
// }
|
||||
|
||||
public:
|
||||
|
||||
GRStateManager(ASTContext& Ctx,
|
||||
StoreManagerCreator CreateStoreManager,
|
||||
ConstraintManagerCreator CreateConstraintManager,
|
||||
llvm::BumpPtrAllocator& alloc, CFG& c,
|
||||
const Decl& cd, LiveVariables& L)
|
||||
: EnvMgr(alloc),
|
||||
ISetFactory(alloc),
|
||||
GDMFactory(alloc),
|
||||
BasicVals(Ctx, alloc),
|
||||
SymMgr(Ctx, alloc),
|
||||
Alloc(alloc),
|
||||
cfg(c),
|
||||
codedecl(cd),
|
||||
Liveness(L) {
|
||||
StoreMgr.reset((*CreateStoreManager)(*this));
|
||||
ConstraintMgr.reset((*CreateConstraintManager)(*this));
|
||||
}
|
||||
|
||||
~GRStateManager();
|
||||
|
||||
const GRState* getInitialState();
|
||||
|
||||
ASTContext& getContext() { return BasicVals.getContext(); }
|
||||
const Decl& getCodeDecl() { return codedecl; }
|
||||
GRTransferFuncs& getTransferFuncs() { return *TF; }
|
||||
BasicValueFactory& getBasicVals() { return BasicVals; }
|
||||
const BasicValueFactory& getBasicVals() const { return BasicVals; }
|
||||
SymbolManager& getSymbolManager() { return SymMgr; }
|
||||
LiveVariables& getLiveVariables() { return Liveness; }
|
||||
llvm::BumpPtrAllocator& getAllocator() { return Alloc; }
|
||||
MemRegionManager& getRegionManager() { return StoreMgr->getRegionManager(); }
|
||||
StoreManager& getStoreManager() { return *StoreMgr; }
|
||||
|
||||
const GRState* BindDecl(const GRState* St, const VarDecl* VD, SVal IVal) {
|
||||
// Store manager should return a persistent state.
|
||||
return StoreMgr->BindDecl(St, VD, IVal);
|
||||
}
|
||||
|
||||
const GRState* BindDeclWithNoInit(const GRState* St, const VarDecl* VD) {
|
||||
// Store manager should return a persistent state.
|
||||
return StoreMgr->BindDeclWithNoInit(St, VD);
|
||||
}
|
||||
|
||||
/// BindCompoundLiteral - Return the state that has the bindings currently
|
||||
/// in 'state' plus the bindings for the CompoundLiteral. 'R' is the region
|
||||
/// for the compound literal and 'BegInit' and 'EndInit' represent an
|
||||
/// array of initializer values.
|
||||
const GRState* BindCompoundLiteral(const GRState* St,
|
||||
const CompoundLiteralExpr* CL, SVal V) {
|
||||
return StoreMgr->BindCompoundLiteral(St, CL, V);
|
||||
}
|
||||
|
||||
const GRState* RemoveDeadBindings(const GRState* St, Stmt* Loc,
|
||||
SymbolReaper& SymReaper);
|
||||
|
||||
const GRState* RemoveSubExprBindings(const GRState* St) {
|
||||
GRState NewSt = *St;
|
||||
NewSt.Env = EnvMgr.RemoveSubExprBindings(NewSt.Env);
|
||||
return getPersistentState(NewSt);
|
||||
}
|
||||
|
||||
|
||||
// Utility methods for getting regions.
|
||||
|
||||
VarRegion* getRegion(const VarDecl* D) {
|
||||
return getRegionManager().getVarRegion(D);
|
||||
}
|
||||
|
||||
const MemRegion* getSelfRegion(const GRState* state) {
|
||||
return StoreMgr->getSelfRegion(state->getStore());
|
||||
}
|
||||
|
||||
// Get the lvalue for a variable reference.
|
||||
SVal GetLValue(const GRState* St, const VarDecl* D) {
|
||||
return StoreMgr->getLValueVar(St, D);
|
||||
}
|
||||
|
||||
// Get the lvalue for a StringLiteral.
|
||||
SVal GetLValue(const GRState* St, const StringLiteral* E) {
|
||||
return StoreMgr->getLValueString(St, E);
|
||||
}
|
||||
|
||||
SVal GetLValue(const GRState* St, const CompoundLiteralExpr* CL) {
|
||||
return StoreMgr->getLValueCompoundLiteral(St, CL);
|
||||
}
|
||||
|
||||
// Get the lvalue for an ivar reference.
|
||||
SVal GetLValue(const GRState* St, const ObjCIvarDecl* D, SVal Base) {
|
||||
return StoreMgr->getLValueIvar(St, D, Base);
|
||||
}
|
||||
|
||||
// Get the lvalue for a field reference.
|
||||
SVal GetLValue(const GRState* St, SVal Base, const FieldDecl* D) {
|
||||
return StoreMgr->getLValueField(St, Base, D);
|
||||
}
|
||||
|
||||
// Get the lvalue for an array index.
|
||||
SVal GetLValue(const GRState* St, SVal Base, SVal Idx) {
|
||||
return StoreMgr->getLValueElement(St, Base, Idx);
|
||||
}
|
||||
|
||||
// Methods that query & manipulate the Environment.
|
||||
|
||||
SVal GetSVal(const GRState* St, Stmt* Ex) {
|
||||
return St->getEnvironment().GetSVal(Ex, BasicVals);
|
||||
}
|
||||
|
||||
SVal GetSVal(const GRState* St, const Stmt* Ex) {
|
||||
return St->getEnvironment().GetSVal(const_cast<Stmt*>(Ex), BasicVals);
|
||||
}
|
||||
|
||||
SVal GetBlkExprSVal(const GRState* St, Stmt* Ex) {
|
||||
return St->getEnvironment().GetBlkExprSVal(Ex, BasicVals);
|
||||
}
|
||||
|
||||
const GRState* BindExpr(const GRState* St, Stmt* Ex, SVal V,
|
||||
bool isBlkExpr, bool Invalidate) {
|
||||
|
||||
const Environment& OldEnv = St->getEnvironment();
|
||||
Environment NewEnv = EnvMgr.BindExpr(OldEnv, Ex, V, isBlkExpr, Invalidate);
|
||||
|
||||
if (NewEnv == OldEnv)
|
||||
return St;
|
||||
|
||||
GRState NewSt = *St;
|
||||
NewSt.Env = NewEnv;
|
||||
return getPersistentState(NewSt);
|
||||
}
|
||||
|
||||
const GRState* BindExpr(const GRState* St, Stmt* Ex, SVal V,
|
||||
bool Invalidate = true) {
|
||||
|
||||
bool isBlkExpr = false;
|
||||
|
||||
if (Ex == CurrentStmt) {
|
||||
// FIXME: Should this just be an assertion? When would we want to set
|
||||
// the value of a block-level expression if it wasn't CurrentStmt?
|
||||
isBlkExpr = cfg.isBlkExpr(Ex);
|
||||
|
||||
if (!isBlkExpr)
|
||||
return St;
|
||||
}
|
||||
|
||||
return BindExpr(St, Ex, V, isBlkExpr, Invalidate);
|
||||
}
|
||||
|
||||
SVal ArrayToPointer(SVal Array) {
|
||||
return StoreMgr->ArrayToPointer(Array);
|
||||
}
|
||||
|
||||
// Methods that manipulate the GDM.
|
||||
const GRState* addGDM(const GRState* St, void* Key, void* Data);
|
||||
|
||||
// Methods that query or create regions.
|
||||
bool hasStackStorage(const MemRegion* R) {
|
||||
return getRegionManager().hasStackStorage(R);
|
||||
}
|
||||
|
||||
// Methods that query & manipulate the Store.
|
||||
|
||||
void iterBindings(const GRState* state, StoreManager::BindingsHandler& F) {
|
||||
StoreMgr->iterBindings(state->getStore(), F);
|
||||
}
|
||||
|
||||
|
||||
SVal GetSVal(const GRState* state, Loc LV, QualType T = QualType()) {
|
||||
return StoreMgr->Retrieve(state, LV, T);
|
||||
}
|
||||
|
||||
SVal GetSVal(const GRState* state, const MemRegion* R) {
|
||||
return StoreMgr->Retrieve(state, loc::MemRegionVal(R));
|
||||
}
|
||||
|
||||
const GRState* BindLoc(const GRState* St, Loc LV, SVal V) {
|
||||
return StoreMgr->Bind(St, LV, V);
|
||||
}
|
||||
|
||||
void Unbind(GRState& St, Loc LV) {
|
||||
St.St = StoreMgr->Remove(St.St, LV);
|
||||
}
|
||||
|
||||
const GRState* Unbind(const GRState* St, Loc LV);
|
||||
|
||||
const GRState* getPersistentState(GRState& Impl);
|
||||
|
||||
// MakeStateWithStore - get a persistent state with the new store.
|
||||
const GRState* MakeStateWithStore(const GRState* St, Store store);
|
||||
|
||||
bool isEqual(const GRState* state, Expr* Ex, const llvm::APSInt& V);
|
||||
bool isEqual(const GRState* state, Expr* Ex, uint64_t);
|
||||
|
||||
|
||||
//==---------------------------------------------------------------------==//
|
||||
// Generic Data Map methods.
|
||||
//==---------------------------------------------------------------------==//
|
||||
//
|
||||
// GRStateManager and GRState support a "generic data map" that allows
|
||||
// different clients of GRState objects to embed arbitrary data within a
|
||||
// GRState object. The generic data map is essentially an immutable map
|
||||
// from a "tag" (that acts as the "key" for a client) and opaque values.
|
||||
// Tags/keys and values are simply void* values. The typical way that clients
|
||||
// generate unique tags are by taking the address of a static variable.
|
||||
// Clients are responsible for ensuring that data values referred to by a
|
||||
// the data pointer are immutable (and thus are essentially purely functional
|
||||
// data).
|
||||
//
|
||||
// The templated methods below use the GRStateTrait<T> class
|
||||
// to resolve keys into the GDM and to return data values to clients.
|
||||
//
|
||||
|
||||
// Trait based GDM dispatch.
|
||||
template <typename T>
|
||||
const GRState* set(const GRState* st, typename GRStateTrait<T>::data_type D) {
|
||||
return addGDM(st, GRStateTrait<T>::GDMIndex(),
|
||||
GRStateTrait<T>::MakeVoidPtr(D));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
const GRState* set(const GRState* st,
|
||||
typename GRStateTrait<T>::key_type K,
|
||||
typename GRStateTrait<T>::value_type V,
|
||||
typename GRStateTrait<T>::context_type C) {
|
||||
|
||||
return addGDM(st, GRStateTrait<T>::GDMIndex(),
|
||||
GRStateTrait<T>::MakeVoidPtr(GRStateTrait<T>::Set(st->get<T>(), K, V, C)));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
const GRState* add(const GRState* st,
|
||||
typename GRStateTrait<T>::key_type K,
|
||||
typename GRStateTrait<T>::context_type C) {
|
||||
return addGDM(st, GRStateTrait<T>::GDMIndex(),
|
||||
GRStateTrait<T>::MakeVoidPtr(GRStateTrait<T>::Add(st->get<T>(), K, C)));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
const GRState* remove(const GRState* st,
|
||||
typename GRStateTrait<T>::key_type K,
|
||||
typename GRStateTrait<T>::context_type C) {
|
||||
|
||||
return addGDM(st, GRStateTrait<T>::GDMIndex(),
|
||||
GRStateTrait<T>::MakeVoidPtr(GRStateTrait<T>::Remove(st->get<T>(), K, C)));
|
||||
}
|
||||
|
||||
|
||||
void* FindGDMContext(void* index,
|
||||
void* (*CreateContext)(llvm::BumpPtrAllocator&),
|
||||
void (*DeleteContext)(void*));
|
||||
|
||||
template <typename T>
|
||||
typename GRStateTrait<T>::context_type get_context() {
|
||||
void* p = FindGDMContext(GRStateTrait<T>::GDMIndex(),
|
||||
GRStateTrait<T>::CreateContext,
|
||||
GRStateTrait<T>::DeleteContext);
|
||||
|
||||
return GRStateTrait<T>::MakeContext(p);
|
||||
}
|
||||
|
||||
//==---------------------------------------------------------------------==//
|
||||
// Constraints on values.
|
||||
//==---------------------------------------------------------------------==//
|
||||
//
|
||||
// Each GRState records constraints on symbolic values. These constraints
|
||||
// are managed using the ConstraintManager associated with a GRStateManager.
|
||||
// As constraints gradually accrue on symbolic values, added constraints
|
||||
// may conflict and indicate that a state is infeasible (as no real values
|
||||
// could satisfy all the constraints). This is the principal mechanism
|
||||
// for modeling path-sensitivity in GRExprEngine/GRState.
|
||||
//
|
||||
// Various "Assume" methods form the interface for adding constraints to
|
||||
// symbolic values. A call to "Assume" indicates an assumption being placed
|
||||
// on one or symbolic values. Assume methods take the following inputs:
|
||||
//
|
||||
// (1) A GRState object representing the current state.
|
||||
//
|
||||
// (2) The assumed constraint (which is specific to a given "Assume" method).
|
||||
//
|
||||
// (3) A binary value "Assumption" that indicates whether the constraint is
|
||||
// assumed to be true or false.
|
||||
//
|
||||
// The output of "Assume" are two values:
|
||||
//
|
||||
// (a) "isFeasible" is set to true or false to indicate whether or not
|
||||
// the assumption is feasible.
|
||||
//
|
||||
// (b) A new GRState object with the added constraints.
|
||||
//
|
||||
// FIXME: (a) should probably disappear since it is redundant with (b).
|
||||
// (i.e., (b) could just be set to NULL).
|
||||
//
|
||||
|
||||
const GRState* Assume(const GRState* St, SVal Cond, bool Assumption,
|
||||
bool& isFeasible) {
|
||||
return ConstraintMgr->Assume(St, Cond, Assumption, isFeasible);
|
||||
}
|
||||
|
||||
const GRState* AssumeInBound(const GRState* St, SVal Idx, SVal UpperBound,
|
||||
bool Assumption, bool& isFeasible) {
|
||||
return ConstraintMgr->AssumeInBound(St, Idx, UpperBound, Assumption,
|
||||
isFeasible);
|
||||
}
|
||||
|
||||
const llvm::APSInt* getSymVal(const GRState* St, SymbolRef sym) {
|
||||
return ConstraintMgr->getSymVal(St, sym);
|
||||
}
|
||||
|
||||
void EndPath(const GRState* St) {
|
||||
ConstraintMgr->EndPath(St);
|
||||
}
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// GRStateRef - A "fat" reference to GRState that also bundles GRStateManager.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
class GRStateRef {
|
||||
const GRState* St;
|
||||
GRStateManager* Mgr;
|
||||
public:
|
||||
GRStateRef(const GRState* st, GRStateManager& mgr) : St(st), Mgr(&mgr) {}
|
||||
|
||||
const GRState* getState() const { return St; }
|
||||
operator const GRState*() const { return St; }
|
||||
GRStateManager& getManager() const { return *Mgr; }
|
||||
|
||||
SVal GetSVal(Expr* Ex) {
|
||||
return Mgr->GetSVal(St, Ex);
|
||||
}
|
||||
|
||||
SVal GetBlkExprSVal(Expr* Ex) {
|
||||
return Mgr->GetBlkExprSVal(St, Ex);
|
||||
}
|
||||
|
||||
SVal GetSVal(Loc LV, QualType T = QualType()) {
|
||||
return Mgr->GetSVal(St, LV, T);
|
||||
}
|
||||
|
||||
SVal GetSVal(const MemRegion* R) {
|
||||
return Mgr->GetSVal(St, R);
|
||||
}
|
||||
|
||||
GRStateRef BindExpr(Stmt* Ex, SVal V, bool isBlkExpr, bool Invalidate) {
|
||||
return GRStateRef(Mgr->BindExpr(St, Ex, V, isBlkExpr, Invalidate), *Mgr);
|
||||
}
|
||||
|
||||
GRStateRef BindExpr(Stmt* Ex, SVal V, bool Invalidate = true) {
|
||||
return GRStateRef(Mgr->BindExpr(St, Ex, V, Invalidate), *Mgr);
|
||||
}
|
||||
|
||||
GRStateRef BindDecl(const VarDecl* VD, SVal InitVal) {
|
||||
return GRStateRef(Mgr->BindDecl(St, VD, InitVal), *Mgr);
|
||||
}
|
||||
|
||||
GRStateRef BindLoc(Loc LV, SVal V) {
|
||||
return GRStateRef(Mgr->BindLoc(St, LV, V), *Mgr);
|
||||
}
|
||||
|
||||
GRStateRef BindLoc(SVal LV, SVal V) {
|
||||
if (!isa<Loc>(LV)) return *this;
|
||||
return BindLoc(cast<Loc>(LV), V);
|
||||
}
|
||||
|
||||
GRStateRef Unbind(Loc LV) {
|
||||
return GRStateRef(Mgr->Unbind(St, LV), *Mgr);
|
||||
}
|
||||
|
||||
// Trait based GDM dispatch.
|
||||
template<typename T>
|
||||
typename GRStateTrait<T>::data_type get() const {
|
||||
return St->get<T>();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
typename GRStateTrait<T>::lookup_type
|
||||
get(typename GRStateTrait<T>::key_type key) const {
|
||||
return St->get<T>(key);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
GRStateRef set(typename GRStateTrait<T>::data_type D) {
|
||||
return GRStateRef(Mgr->set<T>(St, D), *Mgr);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename GRStateTrait<T>::context_type get_context() {
|
||||
return Mgr->get_context<T>();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
GRStateRef set(typename GRStateTrait<T>::key_type K,
|
||||
typename GRStateTrait<T>::value_type E,
|
||||
typename GRStateTrait<T>::context_type C) {
|
||||
return GRStateRef(Mgr->set<T>(St, K, E, C), *Mgr);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
GRStateRef set(typename GRStateTrait<T>::key_type K,
|
||||
typename GRStateTrait<T>::value_type E) {
|
||||
return GRStateRef(Mgr->set<T>(St, K, E, get_context<T>()), *Mgr);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
GRStateRef add(typename GRStateTrait<T>::key_type K) {
|
||||
return GRStateRef(Mgr->add<T>(St, K, get_context<T>()), *Mgr);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
GRStateRef remove(typename GRStateTrait<T>::key_type K,
|
||||
typename GRStateTrait<T>::context_type C) {
|
||||
return GRStateRef(Mgr->remove<T>(St, K, C), *Mgr);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
GRStateRef remove(typename GRStateTrait<T>::key_type K) {
|
||||
return GRStateRef(Mgr->remove<T>(St, K, get_context<T>()), *Mgr);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool contains(typename GRStateTrait<T>::key_type key) const {
|
||||
return St->contains<T>(key);
|
||||
}
|
||||
|
||||
// Lvalue methods.
|
||||
SVal GetLValue(const VarDecl* VD) {
|
||||
return Mgr->GetLValue(St, VD);
|
||||
}
|
||||
|
||||
GRStateRef Assume(SVal Cond, bool Assumption, bool& isFeasible) {
|
||||
return GRStateRef(Mgr->Assume(St, Cond, Assumption, isFeasible), *Mgr);
|
||||
}
|
||||
|
||||
// Pretty-printing.
|
||||
void print(std::ostream& Out, const char* nl = "\n",
|
||||
const char *sep = "") const;
|
||||
|
||||
void printStdErr() const;
|
||||
|
||||
void printDOT(std::ostream& Out) const;
|
||||
};
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
#endif
|
||||
@@ -1,143 +0,0 @@
|
||||
//==- GRStateTrait.h - Partial implementations of GRStateTrait -----*- 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 partial implementations of template specializations of
|
||||
// the class GRStateTrait<>. GRStateTrait<> is used by GRState to implement
|
||||
// set/get methods for mapulating a GRState's generic data map.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSIS_GRSTATETRAIT_H
|
||||
#define LLVM_CLANG_ANALYSIS_GRSTATETRAIT_H
|
||||
|
||||
namespace llvm {
|
||||
class BumpPtrAllocator;
|
||||
template <typename K, typename D, typename I> class ImmutableMap;
|
||||
template <typename K, typename I> class ImmutableSet;
|
||||
template <typename T> class ImmutableList;
|
||||
template <typename T> class ImmutableListImpl;
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
template <typename T> struct GRStatePartialTrait;
|
||||
|
||||
// Partial-specialization for ImmutableMap.
|
||||
|
||||
template <typename Key, typename Data, typename Info>
|
||||
struct GRStatePartialTrait< llvm::ImmutableMap<Key,Data,Info> > {
|
||||
typedef llvm::ImmutableMap<Key,Data,Info> data_type;
|
||||
typedef typename data_type::Factory& context_type;
|
||||
typedef Key key_type;
|
||||
typedef Data value_type;
|
||||
typedef const value_type* lookup_type;
|
||||
|
||||
static inline data_type MakeData(void* const* p) {
|
||||
return p ? data_type((typename data_type::TreeTy*) *p) : data_type(0);
|
||||
}
|
||||
static inline void* MakeVoidPtr(data_type B) {
|
||||
return B.getRoot();
|
||||
}
|
||||
static lookup_type Lookup(data_type B, key_type K) {
|
||||
return B.lookup(K);
|
||||
}
|
||||
static data_type Set(data_type B, key_type K, value_type E,context_type F){
|
||||
return F.Add(B, K, E);
|
||||
}
|
||||
|
||||
static data_type Remove(data_type B, key_type K, context_type F) {
|
||||
return F.Remove(B, K);
|
||||
}
|
||||
|
||||
static inline context_type MakeContext(void* p) {
|
||||
return *((typename data_type::Factory*) p);
|
||||
}
|
||||
|
||||
static void* CreateContext(llvm::BumpPtrAllocator& Alloc) {
|
||||
return new typename data_type::Factory(Alloc);
|
||||
}
|
||||
|
||||
static void DeleteContext(void* Ctx) {
|
||||
delete (typename data_type::Factory*) Ctx;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Partial-specialization for ImmutableSet.
|
||||
|
||||
template <typename Key, typename Info>
|
||||
struct GRStatePartialTrait< llvm::ImmutableSet<Key,Info> > {
|
||||
typedef llvm::ImmutableSet<Key,Info> data_type;
|
||||
typedef typename data_type::Factory& context_type;
|
||||
typedef Key key_type;
|
||||
|
||||
static inline data_type MakeData(void* const* p) {
|
||||
return p ? data_type((typename data_type::TreeTy*) *p) : data_type(0);
|
||||
}
|
||||
|
||||
static inline void* MakeVoidPtr(data_type B) {
|
||||
return B.getRoot();
|
||||
}
|
||||
|
||||
static data_type Add(data_type B, key_type K, context_type F) {
|
||||
return F.Add(B, K);
|
||||
}
|
||||
|
||||
static data_type Remove(data_type B, key_type K, context_type F) {
|
||||
return F.Remove(B, K);
|
||||
}
|
||||
|
||||
static bool Contains(data_type B, key_type K) {
|
||||
return B.contains(K);
|
||||
}
|
||||
|
||||
static inline context_type MakeContext(void* p) {
|
||||
return *((typename data_type::Factory*) p);
|
||||
}
|
||||
|
||||
static void* CreateContext(llvm::BumpPtrAllocator& Alloc) {
|
||||
return new typename data_type::Factory(Alloc);
|
||||
}
|
||||
|
||||
static void DeleteContext(void* Ctx) {
|
||||
delete (typename data_type::Factory*) Ctx;
|
||||
}
|
||||
};
|
||||
|
||||
// Partial-specialization for ImmutableList.
|
||||
|
||||
template <typename T>
|
||||
struct GRStatePartialTrait< llvm::ImmutableList<T> > {
|
||||
typedef llvm::ImmutableList<T> data_type;
|
||||
typedef typename data_type::Factory& context_type;
|
||||
|
||||
static inline data_type MakeData(void* const* p) {
|
||||
return p ? data_type((const llvm::ImmutableListImpl<T>*) *p)
|
||||
: data_type(0);
|
||||
}
|
||||
|
||||
static inline void* MakeVoidPtr(data_type D) {
|
||||
return (void*) D.getInternalPointer();
|
||||
}
|
||||
|
||||
static inline context_type MakeContext(void* p) {
|
||||
return *((typename data_type::Factory*) p);
|
||||
}
|
||||
|
||||
static void* CreateContext(llvm::BumpPtrAllocator& Alloc) {
|
||||
return new typename data_type::Factory(Alloc);
|
||||
}
|
||||
|
||||
static void DeleteContext(void* Ctx) {
|
||||
delete (typename data_type::Factory*) Ctx;
|
||||
}
|
||||
};
|
||||
} // end clang namespace
|
||||
|
||||
#endif
|
||||
@@ -1,133 +0,0 @@
|
||||
//== GRTransferFuncs.h - Path-Sens. Transfer Functions Interface -*- 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 GRTransferFuncs, which provides a base-class that
|
||||
// defines an interface for transfer functions used by GRExprEngine.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSIS_GRTF
|
||||
#define LLVM_CLANG_ANALYSIS_GRTF
|
||||
|
||||
#include "clang/Analysis/PathSensitive/SVals.h"
|
||||
#include "clang/Analysis/PathSensitive/GRCoreEngine.h"
|
||||
#include "clang/Analysis/PathSensitive/GRState.h"
|
||||
#include <vector>
|
||||
|
||||
namespace clang {
|
||||
|
||||
class GRExprEngine;
|
||||
class ObjCMessageExpr;
|
||||
|
||||
class GRTransferFuncs {
|
||||
|
||||
friend class GRExprEngine;
|
||||
|
||||
protected:
|
||||
|
||||
|
||||
virtual SVal DetermEvalBinOpNN(GRExprEngine& Eng,
|
||||
BinaryOperator::Opcode Op,
|
||||
NonLoc L, NonLoc R) {
|
||||
return UnknownVal();
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
GRTransferFuncs() {}
|
||||
virtual ~GRTransferFuncs() {}
|
||||
|
||||
virtual void RegisterPrinters(std::vector<GRState::Printer*>& Printers) {}
|
||||
virtual void RegisterChecks(GRExprEngine& Eng);
|
||||
|
||||
// Casts.
|
||||
|
||||
virtual SVal EvalCast(GRExprEngine& Engine, NonLoc V, QualType CastT) =0;
|
||||
virtual SVal EvalCast(GRExprEngine& Engine, Loc V, QualType CastT) = 0;
|
||||
|
||||
// Unary Operators.
|
||||
|
||||
virtual SVal EvalMinus(GRExprEngine& Engine, UnaryOperator* U, NonLoc X) = 0;
|
||||
|
||||
virtual SVal EvalComplement(GRExprEngine& Engine, NonLoc X) = 0;
|
||||
|
||||
// Binary Operators.
|
||||
// FIXME: We're moving back towards using GREXprEngine directly. No need
|
||||
// for OStates
|
||||
virtual void EvalBinOpNN(GRStateSet& OStates, GRExprEngine& Eng,
|
||||
const GRState* St, Expr* Ex,
|
||||
BinaryOperator::Opcode Op, NonLoc L, NonLoc R);
|
||||
|
||||
virtual SVal EvalBinOp(GRExprEngine& Engine, BinaryOperator::Opcode Op,
|
||||
Loc L, Loc R) = 0;
|
||||
|
||||
// Pointer arithmetic.
|
||||
|
||||
virtual SVal EvalBinOp(GRExprEngine& Engine, BinaryOperator::Opcode Op,
|
||||
Loc L, NonLoc R) = 0;
|
||||
|
||||
// Calls.
|
||||
|
||||
virtual void EvalCall(ExplodedNodeSet<GRState>& Dst,
|
||||
GRExprEngine& Engine,
|
||||
GRStmtNodeBuilder<GRState>& Builder,
|
||||
CallExpr* CE, SVal L,
|
||||
ExplodedNode<GRState>* Pred) {}
|
||||
|
||||
virtual void EvalObjCMessageExpr(ExplodedNodeSet<GRState>& Dst,
|
||||
GRExprEngine& Engine,
|
||||
GRStmtNodeBuilder<GRState>& Builder,
|
||||
ObjCMessageExpr* ME,
|
||||
ExplodedNode<GRState>* Pred) {}
|
||||
|
||||
// Stores.
|
||||
|
||||
/// EvalStore - Evaluate the effects of a store, creating a new node
|
||||
/// the represents the effect of binding 'Val' to the location 'TargetLV'.
|
||||
// TargetLV is guaranteed to either be an UnknownVal or an Loc.
|
||||
virtual void EvalStore(ExplodedNodeSet<GRState>& Dst,
|
||||
GRExprEngine& Engine,
|
||||
GRStmtNodeBuilder<GRState>& Builder,
|
||||
Expr* E, ExplodedNode<GRState>* Pred,
|
||||
const GRState* St, SVal TargetLV, SVal Val);
|
||||
|
||||
|
||||
// End-of-path and dead symbol notification.
|
||||
|
||||
virtual void EvalEndPath(GRExprEngine& Engine,
|
||||
GREndPathNodeBuilder<GRState>& Builder) {}
|
||||
|
||||
|
||||
virtual void EvalDeadSymbols(ExplodedNodeSet<GRState>& Dst,
|
||||
GRExprEngine& Engine,
|
||||
GRStmtNodeBuilder<GRState>& Builder,
|
||||
ExplodedNode<GRState>* Pred,
|
||||
Stmt* S, const GRState* state,
|
||||
SymbolReaper& SymReaper) {}
|
||||
|
||||
// Return statements.
|
||||
virtual void EvalReturn(ExplodedNodeSet<GRState>& Dst,
|
||||
GRExprEngine& Engine,
|
||||
GRStmtNodeBuilder<GRState>& Builder,
|
||||
ReturnStmt* S,
|
||||
ExplodedNode<GRState>* Pred) {}
|
||||
|
||||
// Assumptions.
|
||||
|
||||
virtual const GRState* EvalAssume(GRStateManager& VMgr,
|
||||
const GRState* St,
|
||||
SVal Cond, bool Assumption,
|
||||
bool& isFeasible) {
|
||||
return St;
|
||||
}
|
||||
};
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
#endif
|
||||
@@ -1,75 +0,0 @@
|
||||
//==- GRWorkList.h - Worklist class used by GRCoreEngine -----------*- C++ -*-//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines GRWorkList, a pure virtual class that represents an opaque
|
||||
// worklist used by GRCoreEngine to explore the reachability state space.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSIS_GRWORKLIST
|
||||
#define LLVM_CLANG_ANALYSIS_GRWORKLIST
|
||||
|
||||
#include "clang/Analysis/PathSensitive/GRBlockCounter.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
class ExplodedNodeImpl;
|
||||
|
||||
class GRWorkListUnit {
|
||||
ExplodedNodeImpl* Node;
|
||||
GRBlockCounter Counter;
|
||||
CFGBlock* Block;
|
||||
unsigned BlockIdx;
|
||||
|
||||
public:
|
||||
GRWorkListUnit(ExplodedNodeImpl* N, GRBlockCounter C,
|
||||
CFGBlock* B, unsigned idx)
|
||||
: Node(N),
|
||||
Counter(C),
|
||||
Block(B),
|
||||
BlockIdx(idx) {}
|
||||
|
||||
explicit GRWorkListUnit(ExplodedNodeImpl* N, GRBlockCounter C)
|
||||
: Node(N),
|
||||
Counter(C),
|
||||
Block(NULL),
|
||||
BlockIdx(0) {}
|
||||
|
||||
ExplodedNodeImpl* getNode() const { return Node; }
|
||||
GRBlockCounter getBlockCounter() const { return Counter; }
|
||||
CFGBlock* getBlock() const { return Block; }
|
||||
unsigned getIndex() const { return BlockIdx; }
|
||||
};
|
||||
|
||||
class GRWorkList {
|
||||
GRBlockCounter CurrentCounter;
|
||||
public:
|
||||
virtual ~GRWorkList();
|
||||
virtual bool hasWork() const = 0;
|
||||
|
||||
virtual void Enqueue(const GRWorkListUnit& U) = 0;
|
||||
|
||||
void Enqueue(ExplodedNodeImpl* N, CFGBlock& B, unsigned idx) {
|
||||
Enqueue(GRWorkListUnit(N, CurrentCounter, &B, idx));
|
||||
}
|
||||
|
||||
void Enqueue(ExplodedNodeImpl* N) {
|
||||
Enqueue(GRWorkListUnit(N, CurrentCounter));
|
||||
}
|
||||
|
||||
virtual GRWorkListUnit Dequeue() = 0;
|
||||
|
||||
void setBlockCounter(GRBlockCounter C) { CurrentCounter = C; }
|
||||
GRBlockCounter getBlockCounter() const { return CurrentCounter; }
|
||||
|
||||
static GRWorkList* MakeDFS();
|
||||
static GRWorkList* MakeBFSBlockDFSContents();
|
||||
};
|
||||
} // end clang namespace
|
||||
#endif
|
||||
@@ -1,535 +0,0 @@
|
||||
//== MemRegion.h - Abstract memory regions for static analysis --*- C++ -*--==//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines MemRegion and its subclasses. MemRegion defines a
|
||||
// partially-typed abstraction of memory useful for path-sensitive dataflow
|
||||
// analyses.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSIS_MEMREGION_H
|
||||
#define LLVM_CLANG_ANALYSIS_MEMREGION_H
|
||||
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/DeclObjC.h"
|
||||
#include "clang/Analysis/PathSensitive/SymbolManager.h"
|
||||
#include "clang/Analysis/PathSensitive/SVals.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
#include "llvm/ADT/ImmutableList.h"
|
||||
#include "llvm/ADT/ImmutableMap.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include <string>
|
||||
|
||||
namespace llvm { class raw_ostream; }
|
||||
|
||||
namespace clang {
|
||||
|
||||
class MemRegionManager;
|
||||
|
||||
|
||||
/// MemRegion - The root abstract class for all memory regions.
|
||||
class MemRegion : public llvm::FoldingSetNode {
|
||||
public:
|
||||
enum Kind { MemSpaceRegionKind, SymbolicRegionKind,
|
||||
AllocaRegionKind,
|
||||
// Typed regions.
|
||||
BEG_TYPED_REGIONS,
|
||||
CompoundLiteralRegionKind,
|
||||
StringRegionKind, ElementRegionKind,
|
||||
AnonTypedRegionKind,
|
||||
AnonPointeeRegionKind,
|
||||
// Decl Regions.
|
||||
BEG_DECL_REGIONS,
|
||||
VarRegionKind, FieldRegionKind,
|
||||
ObjCIvarRegionKind, ObjCObjectRegionKind,
|
||||
END_DECL_REGIONS,
|
||||
END_TYPED_REGIONS };
|
||||
private:
|
||||
const Kind kind;
|
||||
|
||||
protected:
|
||||
MemRegion(Kind k) : kind(k) {}
|
||||
virtual ~MemRegion();
|
||||
|
||||
public:
|
||||
// virtual MemExtent getExtent(MemRegionManager& mrm) const = 0;
|
||||
virtual void Profile(llvm::FoldingSetNodeID& ID) const = 0;
|
||||
|
||||
std::string getString() const;
|
||||
|
||||
virtual void print(llvm::raw_ostream& os) const;
|
||||
|
||||
Kind getKind() const { return kind; }
|
||||
|
||||
static bool classof(const MemRegion*) { return true; }
|
||||
};
|
||||
|
||||
/// MemSpaceRegion - A memory region that represents and "memory space";
|
||||
/// for example, the set of global variables, the stack frame, etc.
|
||||
class MemSpaceRegion : public MemRegion {
|
||||
friend class MemRegionManager;
|
||||
MemSpaceRegion() : MemRegion(MemSpaceRegionKind) {}
|
||||
|
||||
public:
|
||||
//RegionExtent getExtent() const { return UndefinedExtent(); }
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID& ID) const;
|
||||
|
||||
static bool classof(const MemRegion* R) {
|
||||
return R->getKind() == MemSpaceRegionKind;
|
||||
}
|
||||
};
|
||||
|
||||
/// SubRegion - A region that subsets another larger region. Most regions
|
||||
/// are subclasses of SubRegion.
|
||||
class SubRegion : public MemRegion {
|
||||
protected:
|
||||
const MemRegion* superRegion;
|
||||
SubRegion(const MemRegion* sReg, Kind k) : MemRegion(k), superRegion(sReg) {}
|
||||
|
||||
public:
|
||||
const MemRegion* getSuperRegion() const {
|
||||
return superRegion;
|
||||
}
|
||||
|
||||
bool isSubRegionOf(const MemRegion* R) const;
|
||||
|
||||
static bool classof(const MemRegion* R) {
|
||||
return R->getKind() > SymbolicRegionKind;
|
||||
}
|
||||
};
|
||||
|
||||
/// AllocaRegion - A region that represents an untyped blob of bytes created
|
||||
/// by a call to 'alloca'.
|
||||
class AllocaRegion : public SubRegion {
|
||||
friend class MemRegionManager;
|
||||
protected:
|
||||
unsigned Cnt; // Block counter. Used to distinguish different pieces of
|
||||
// memory allocated by alloca at the same call site.
|
||||
const Expr* Ex;
|
||||
|
||||
AllocaRegion(const Expr* ex, unsigned cnt, const MemRegion* superRegion)
|
||||
: SubRegion(superRegion, AllocaRegionKind), Cnt(cnt), Ex(ex) {}
|
||||
|
||||
public:
|
||||
|
||||
const Expr* getExpr() const { return Ex; }
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID& ID) const;
|
||||
|
||||
static void ProfileRegion(llvm::FoldingSetNodeID& ID, const Expr* Ex,
|
||||
unsigned Cnt);
|
||||
|
||||
void print(llvm::raw_ostream& os) const;
|
||||
|
||||
static bool classof(const MemRegion* R) {
|
||||
return R->getKind() == AllocaRegionKind;
|
||||
}
|
||||
};
|
||||
|
||||
/// SymbolicRegion - A special, "non-concrete" region. Unlike other region
|
||||
/// clases, SymbolicRegion represents a region that serves as an alias for
|
||||
/// either a real region, a NULL pointer, etc. It essentially is used to
|
||||
/// map the concept of symbolic values into the domain of regions. Symbolic
|
||||
/// regions do not need to be typed.
|
||||
class SymbolicRegion : public MemRegion {
|
||||
protected:
|
||||
const SymbolRef sym;
|
||||
|
||||
public:
|
||||
SymbolicRegion(const SymbolRef s) : MemRegion(SymbolicRegionKind), sym(s) {}
|
||||
|
||||
SymbolRef getSymbol() const {
|
||||
return sym;
|
||||
}
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID& ID) const;
|
||||
static void ProfileRegion(llvm::FoldingSetNodeID& ID, SymbolRef sym);
|
||||
|
||||
void print(llvm::raw_ostream& os) const;
|
||||
|
||||
static bool classof(const MemRegion* R) {
|
||||
return R->getKind() == SymbolicRegionKind;
|
||||
}
|
||||
};
|
||||
|
||||
/// TypedRegion - An abstract class representing regions that are typed.
|
||||
class TypedRegion : public SubRegion {
|
||||
protected:
|
||||
TypedRegion(const MemRegion* sReg, Kind k) : SubRegion(sReg, k) {}
|
||||
|
||||
public:
|
||||
virtual QualType getRValueType(ASTContext &C) const = 0;
|
||||
|
||||
virtual QualType getLValueType(ASTContext& C) const {
|
||||
// FIXME: We can possibly optimize this later to cache this value.
|
||||
return C.getPointerType(getRValueType(C));
|
||||
}
|
||||
|
||||
QualType getDesugaredRValueType(ASTContext& C) const {
|
||||
return getRValueType(C)->getDesugaredType();
|
||||
}
|
||||
|
||||
QualType getDesugaredLValueType(ASTContext& C) const {
|
||||
return getLValueType(C)->getDesugaredType();
|
||||
}
|
||||
|
||||
static bool classof(const MemRegion* R) {
|
||||
unsigned k = R->getKind();
|
||||
return k > BEG_TYPED_REGIONS && k < END_TYPED_REGIONS;
|
||||
}
|
||||
};
|
||||
|
||||
/// StringRegion - Region associated with a StringLiteral.
|
||||
class StringRegion : public TypedRegion {
|
||||
friend class MemRegionManager;
|
||||
const StringLiteral* Str;
|
||||
protected:
|
||||
|
||||
StringRegion(const StringLiteral* str, MemRegion* sreg)
|
||||
: TypedRegion(sreg, StringRegionKind), Str(str) {}
|
||||
|
||||
static void ProfileRegion(llvm::FoldingSetNodeID& ID,
|
||||
const StringLiteral* Str,
|
||||
const MemRegion* superRegion);
|
||||
|
||||
public:
|
||||
|
||||
const StringLiteral* getStringLiteral() const { return Str; }
|
||||
|
||||
QualType getRValueType(ASTContext& C) const;
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID& ID) const {
|
||||
ProfileRegion(ID, Str, superRegion);
|
||||
}
|
||||
|
||||
void print(llvm::raw_ostream& os) const;
|
||||
|
||||
static bool classof(const MemRegion* R) {
|
||||
return R->getKind() == StringRegionKind;
|
||||
}
|
||||
};
|
||||
|
||||
class AnonTypedRegion : public TypedRegion {
|
||||
friend class MemRegionManager;
|
||||
|
||||
QualType T;
|
||||
|
||||
AnonTypedRegion(QualType t, const MemRegion* sreg)
|
||||
: TypedRegion(sreg, AnonTypedRegionKind), T(t) {}
|
||||
|
||||
static void ProfileRegion(llvm::FoldingSetNodeID& ID, QualType T,
|
||||
const MemRegion* superRegion);
|
||||
|
||||
public:
|
||||
|
||||
void print(llvm::raw_ostream& os) const;
|
||||
|
||||
QualType getRValueType(ASTContext&) const {
|
||||
return T;
|
||||
}
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID& ID) const {
|
||||
ProfileRegion(ID, T, superRegion);
|
||||
}
|
||||
|
||||
static bool classof(const MemRegion* R) {
|
||||
return R->getKind() == AnonTypedRegionKind;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/// CompoundLiteralRegion - A memory region representing a compound literal.
|
||||
/// Compound literals are essentially temporaries that are stack allocated
|
||||
/// or in the global constant pool.
|
||||
class CompoundLiteralRegion : public TypedRegion {
|
||||
private:
|
||||
friend class MemRegionManager;
|
||||
const CompoundLiteralExpr* CL;
|
||||
|
||||
CompoundLiteralRegion(const CompoundLiteralExpr* cl, const MemRegion* sReg)
|
||||
: TypedRegion(sReg, CompoundLiteralRegionKind), CL(cl) {}
|
||||
|
||||
static void ProfileRegion(llvm::FoldingSetNodeID& ID,
|
||||
const CompoundLiteralExpr* CL,
|
||||
const MemRegion* superRegion);
|
||||
public:
|
||||
QualType getRValueType(ASTContext& C) const {
|
||||
return C.getCanonicalType(CL->getType());
|
||||
}
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID& ID) const;
|
||||
|
||||
void print(llvm::raw_ostream& os) const;
|
||||
|
||||
const CompoundLiteralExpr* getLiteralExpr() const { return CL; }
|
||||
|
||||
static bool classof(const MemRegion* R) {
|
||||
return R->getKind() == CompoundLiteralRegionKind;
|
||||
}
|
||||
};
|
||||
|
||||
class DeclRegion : public TypedRegion {
|
||||
protected:
|
||||
const Decl* D;
|
||||
|
||||
DeclRegion(const Decl* d, const MemRegion* sReg, Kind k)
|
||||
: TypedRegion(sReg, k), D(d) {}
|
||||
|
||||
static void ProfileRegion(llvm::FoldingSetNodeID& ID, const Decl* D,
|
||||
const MemRegion* superRegion, Kind k);
|
||||
|
||||
public:
|
||||
const Decl* getDecl() const { return D; }
|
||||
void Profile(llvm::FoldingSetNodeID& ID) const;
|
||||
|
||||
QualType getRValueType(ASTContext& C) const = 0;
|
||||
|
||||
static bool classof(const MemRegion* R) {
|
||||
unsigned k = R->getKind();
|
||||
return k > BEG_DECL_REGIONS && k < END_DECL_REGIONS;
|
||||
}
|
||||
};
|
||||
|
||||
class VarRegion : public DeclRegion {
|
||||
friend class MemRegionManager;
|
||||
|
||||
VarRegion(const VarDecl* vd, const MemRegion* sReg)
|
||||
: DeclRegion(vd, sReg, VarRegionKind) {}
|
||||
|
||||
static void ProfileRegion(llvm::FoldingSetNodeID& ID, VarDecl* VD,
|
||||
const MemRegion* superRegion) {
|
||||
DeclRegion::ProfileRegion(ID, VD, superRegion, VarRegionKind);
|
||||
}
|
||||
|
||||
public:
|
||||
const VarDecl* getDecl() const { return cast<VarDecl>(D); }
|
||||
|
||||
QualType getRValueType(ASTContext& C) const {
|
||||
// FIXME: We can cache this if needed.
|
||||
return C.getCanonicalType(getDecl()->getType());
|
||||
}
|
||||
|
||||
void print(llvm::raw_ostream& os) const;
|
||||
|
||||
static bool classof(const MemRegion* R) {
|
||||
return R->getKind() == VarRegionKind;
|
||||
}
|
||||
};
|
||||
|
||||
class FieldRegion : public DeclRegion {
|
||||
friend class MemRegionManager;
|
||||
|
||||
FieldRegion(const FieldDecl* fd, const MemRegion* sReg)
|
||||
: DeclRegion(fd, sReg, FieldRegionKind) {}
|
||||
|
||||
public:
|
||||
|
||||
void print(llvm::raw_ostream& os) const;
|
||||
|
||||
const FieldDecl* getDecl() const { return cast<FieldDecl>(D); }
|
||||
|
||||
QualType getRValueType(ASTContext& C) const {
|
||||
// FIXME: We can cache this if needed.
|
||||
return C.getCanonicalType(getDecl()->getType());
|
||||
}
|
||||
|
||||
static void ProfileRegion(llvm::FoldingSetNodeID& ID, FieldDecl* FD,
|
||||
const MemRegion* superRegion) {
|
||||
DeclRegion::ProfileRegion(ID, FD, superRegion, FieldRegionKind);
|
||||
}
|
||||
|
||||
static bool classof(const MemRegion* R) {
|
||||
return R->getKind() == FieldRegionKind;
|
||||
}
|
||||
};
|
||||
|
||||
class ObjCObjectRegion : public DeclRegion {
|
||||
|
||||
friend class MemRegionManager;
|
||||
|
||||
ObjCObjectRegion(const ObjCInterfaceDecl* ivd, const MemRegion* sReg)
|
||||
: DeclRegion(ivd, sReg, ObjCObjectRegionKind) {}
|
||||
|
||||
static void ProfileRegion(llvm::FoldingSetNodeID& ID, ObjCInterfaceDecl* ivd,
|
||||
const MemRegion* superRegion) {
|
||||
DeclRegion::ProfileRegion(ID, ivd, superRegion, ObjCObjectRegionKind);
|
||||
}
|
||||
|
||||
public:
|
||||
const ObjCInterfaceDecl* getInterface() const {
|
||||
return cast<ObjCInterfaceDecl>(D);
|
||||
}
|
||||
|
||||
QualType getRValueType(ASTContext& C) const {
|
||||
ObjCInterfaceDecl* ID = const_cast<ObjCInterfaceDecl*>(getInterface());
|
||||
return C.getObjCInterfaceType(ID);
|
||||
}
|
||||
|
||||
static bool classof(const MemRegion* R) {
|
||||
return R->getKind() == ObjCObjectRegionKind;
|
||||
}
|
||||
};
|
||||
|
||||
class ObjCIvarRegion : public DeclRegion {
|
||||
|
||||
friend class MemRegionManager;
|
||||
|
||||
ObjCIvarRegion(const ObjCIvarDecl* ivd, const MemRegion* sReg)
|
||||
: DeclRegion(ivd, sReg, ObjCIvarRegionKind) {}
|
||||
|
||||
static void ProfileRegion(llvm::FoldingSetNodeID& ID, ObjCIvarDecl* ivd,
|
||||
const MemRegion* superRegion) {
|
||||
DeclRegion::ProfileRegion(ID, ivd, superRegion, ObjCIvarRegionKind);
|
||||
}
|
||||
|
||||
public:
|
||||
const ObjCIvarDecl* getDecl() const { return cast<ObjCIvarDecl>(D); }
|
||||
QualType getRValueType(ASTContext&) const { return getDecl()->getType(); }
|
||||
|
||||
static bool classof(const MemRegion* R) {
|
||||
return R->getKind() == ObjCIvarRegionKind;
|
||||
}
|
||||
};
|
||||
|
||||
class ElementRegion : public TypedRegion {
|
||||
friend class MemRegionManager;
|
||||
|
||||
SVal Index;
|
||||
|
||||
ElementRegion(SVal Idx, const MemRegion* sReg)
|
||||
: TypedRegion(sReg, ElementRegionKind), Index(Idx) {
|
||||
assert((!isa<nonloc::ConcreteInt>(&Idx) ||
|
||||
cast<nonloc::ConcreteInt>(&Idx)->getValue().isSigned()) &&
|
||||
"The index must be signed");
|
||||
}
|
||||
|
||||
static void ProfileRegion(llvm::FoldingSetNodeID& ID, SVal Idx,
|
||||
const MemRegion* superRegion);
|
||||
|
||||
public:
|
||||
|
||||
SVal getIndex() const { return Index; }
|
||||
|
||||
QualType getRValueType(ASTContext&) const;
|
||||
|
||||
/// getArrayRegion - Return the region of the enclosing array. This is
|
||||
/// the same as getSuperRegion() except that this returns a TypedRegion*
|
||||
/// instead of a MemRegion*.
|
||||
const TypedRegion* getArrayRegion() const {
|
||||
return cast<TypedRegion>(getSuperRegion());
|
||||
}
|
||||
|
||||
void print(llvm::raw_ostream& os) const;
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID& ID) const;
|
||||
|
||||
static bool classof(const MemRegion* R) {
|
||||
return R->getKind() == ElementRegionKind;
|
||||
}
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// MemRegionManager - Factory object for creating regions.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
class MemRegionManager {
|
||||
llvm::BumpPtrAllocator& A;
|
||||
llvm::FoldingSet<MemRegion> Regions;
|
||||
|
||||
MemSpaceRegion* globals;
|
||||
MemSpaceRegion* stack;
|
||||
MemSpaceRegion* heap;
|
||||
MemSpaceRegion* unknown;
|
||||
|
||||
public:
|
||||
MemRegionManager(llvm::BumpPtrAllocator& a)
|
||||
: A(a), globals(0), stack(0), heap(0), unknown(0) {}
|
||||
|
||||
~MemRegionManager() {}
|
||||
|
||||
/// getStackRegion - Retrieve the memory region associated with the
|
||||
/// current stack frame.
|
||||
MemSpaceRegion* getStackRegion();
|
||||
|
||||
/// getGlobalsRegion - Retrieve the memory region associated with
|
||||
/// all global variables.
|
||||
MemSpaceRegion* getGlobalsRegion();
|
||||
|
||||
/// getHeapRegion - Retrieve the memory region associated with the
|
||||
/// generic "heap".
|
||||
MemSpaceRegion* getHeapRegion();
|
||||
|
||||
/// getUnknownRegion - Retrieve the memory region associated with unknown
|
||||
/// memory space.
|
||||
MemSpaceRegion* getUnknownRegion();
|
||||
|
||||
bool isGlobalsRegion(const MemRegion* R) {
|
||||
assert(R);
|
||||
return R == globals;
|
||||
}
|
||||
|
||||
/// onStack - check if the region is allocated on the stack.
|
||||
bool onStack(const MemRegion* R);
|
||||
|
||||
/// onHeap - check if the region is allocated on the heap, usually by malloc.
|
||||
bool onHeap(const MemRegion* R);
|
||||
|
||||
/// getAllocaRegion - Retrieve a region associated with a call to alloca().
|
||||
AllocaRegion* getAllocaRegion(const Expr* Ex, unsigned Cnt);
|
||||
|
||||
/// getCompoundLiteralRegion - Retrieve the region associated with a
|
||||
/// given CompoundLiteral.
|
||||
CompoundLiteralRegion*
|
||||
getCompoundLiteralRegion(const CompoundLiteralExpr* CL);
|
||||
|
||||
/// getSymbolicRegion - Retrieve or create a "symbolic" memory region.
|
||||
SymbolicRegion* getSymbolicRegion(const SymbolRef sym);
|
||||
|
||||
StringRegion* getStringRegion(const StringLiteral* Str);
|
||||
|
||||
/// getVarRegion - Retrieve or create the memory region associated with
|
||||
/// a specified VarDecl.
|
||||
VarRegion* getVarRegion(const VarDecl* vd);
|
||||
|
||||
ElementRegion* getElementRegion(SVal Idx, const TypedRegion* superRegion);
|
||||
|
||||
/// getFieldRegion - Retrieve or create the memory region associated with
|
||||
/// a specified FieldDecl. 'superRegion' corresponds to the containing
|
||||
/// memory region (which typically represents the memory representing
|
||||
/// a structure or class).
|
||||
FieldRegion* getFieldRegion(const FieldDecl* fd,
|
||||
const MemRegion* superRegion);
|
||||
|
||||
/// getObjCObjectRegion - Retrieve or create the memory region associated with
|
||||
/// the instance of a specified Objective-C class.
|
||||
ObjCObjectRegion* getObjCObjectRegion(const ObjCInterfaceDecl* ID,
|
||||
const MemRegion* superRegion);
|
||||
|
||||
/// getObjCIvarRegion - Retrieve or create the memory region associated with
|
||||
/// a specified Objective-c instance variable. 'superRegion' corresponds
|
||||
/// to the containing region (which typically represents the Objective-C
|
||||
/// object).
|
||||
ObjCIvarRegion* getObjCIvarRegion(const ObjCIvarDecl* ivd,
|
||||
const MemRegion* superRegion);
|
||||
|
||||
AnonTypedRegion* getAnonTypedRegion(QualType t, const MemRegion* superRegion);
|
||||
|
||||
bool hasStackStorage(const MemRegion* R);
|
||||
|
||||
private:
|
||||
MemSpaceRegion* LazyAllocate(MemSpaceRegion*& region);
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // end clang namespace
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user