Compare commits
35 Commits
llvmorg-4.
...
llvmorg-2.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5f298e09ca | ||
|
|
0af63acf2b | ||
|
|
494e9178d4 | ||
|
|
7724c67a1f | ||
|
|
8c2ae4c603 | ||
|
|
53c8de3f31 | ||
|
|
c46ec58ffc | ||
|
|
1827f38015 | ||
|
|
8ba6114ae4 | ||
|
|
9768c466b5 | ||
|
|
51132465ec | ||
|
|
b45f183f00 | ||
|
|
84a01a6002 | ||
|
|
2e505e9a4f | ||
|
|
a4bd3bf1bf | ||
|
|
b2794155c8 | ||
|
|
2bf32ce994 | ||
|
|
50e5d261c0 | ||
|
|
b69f6c0254 | ||
|
|
32d5a24bcc | ||
|
|
83d2dae0be | ||
|
|
b3b4f8ec71 | ||
|
|
026efad9ee | ||
|
|
2c1543b929 | ||
|
|
d023218880 | ||
|
|
96a7af38fc | ||
|
|
71a98c5b27 | ||
|
|
b42f087791 | ||
|
|
de2ede8989 | ||
|
|
d4a2592bbc | ||
|
|
26827b525b | ||
|
|
5966839fcf | ||
|
|
956d83f5ae | ||
|
|
bd0bb54410 | ||
|
|
4ee26f1ed6 |
@@ -1,734 +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/HTMLDiagnostics.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/Bitcode/ReaderWriter.h"
|
||||
#include "llvm/Support/Streams.h"
|
||||
#include "llvm/Support/Timer.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
#include <fstream>
|
||||
|
||||
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->getName();
|
||||
}
|
||||
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->getName();
|
||||
}
|
||||
Out << ";\n";
|
||||
} else if (TagDecl *TD = dyn_cast<TagDecl>(D)) {
|
||||
Out << "Read top-level tag decl: '" << TD->getName() << "'\n";
|
||||
} else if (ScopedDecl *SD = dyn_cast<ScopedDecl>(D)) {
|
||||
Out << "Read top-level variable decl: '" << SD->getName() << "'\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 {
|
||||
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->getName();
|
||||
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)->getName();
|
||||
|
||||
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->getName();
|
||||
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 << "\" { ";
|
||||
PrintDecl(LS->getDecl());
|
||||
Out << "}\n";
|
||||
}
|
||||
|
||||
void DeclPrinter::PrintObjCMethodDecl(ObjCMethodDecl *OMD) {
|
||||
if (OMD->isInstance())
|
||||
Out << "\n- ";
|
||||
else
|
||||
Out << "\n+ ";
|
||||
if (!OMD->getResultType().isNull())
|
||||
Out << '(' << OMD->getResultType().getAsString() << ")";
|
||||
|
||||
std::string name = OMD->getSelector().getName();
|
||||
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->getName();
|
||||
lastPos = pos + 1;
|
||||
}
|
||||
|
||||
if (OMD->getNumParams() == 0)
|
||||
Out << " " << name;
|
||||
|
||||
if (OMD->isVariadic())
|
||||
Out << ", ...";
|
||||
|
||||
Out << ";";
|
||||
}
|
||||
|
||||
void DeclPrinter::PrintObjCImplementationDecl(ObjCImplementationDecl *OID) {
|
||||
std::string I = OID->getName();
|
||||
ObjCInterfaceDecl *SID = OID->getSuperClass();
|
||||
|
||||
if (SID)
|
||||
Out << "@implementation " << I << " : " << SID->getName();
|
||||
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->getName();
|
||||
ObjCInterfaceDecl *SID = OID->getSuperClass();
|
||||
|
||||
if (SID)
|
||||
Out << "@interface " << I << " : " << SID->getName();
|
||||
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)->getName();
|
||||
}
|
||||
|
||||
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)->getName() << ";\n";
|
||||
}
|
||||
Out << "}\n";
|
||||
}
|
||||
|
||||
for (ObjCInterfaceDecl::classprop_iterator I = OID->classprop_begin(),
|
||||
E = OID->classprop_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->getName() << '\n';
|
||||
|
||||
for (ObjCProtocolDecl::classprop_iterator I = PID->classprop_begin(),
|
||||
E = PID->classprop_end(); I != E; ++I)
|
||||
PrintObjCPropertyDecl(*I);
|
||||
Out << "@end\n";
|
||||
// FIXME: implement the rest...
|
||||
}
|
||||
|
||||
void DeclPrinter::PrintObjCCategoryImplDecl(ObjCCategoryImplDecl *PID) {
|
||||
Out << "@implementation "
|
||||
<< PID->getClassInterface()->getName()
|
||||
<< '(' << PID->getName() << ");\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()->getName()
|
||||
<< '(' << PID->getName() << ");\n";
|
||||
// Output property declarations.
|
||||
for (ObjCCategoryDecl::classprop_iterator I = PID->classprop_begin(),
|
||||
E = PID->classprop_end(); I != E; ++I)
|
||||
PrintObjCPropertyDecl(*I);
|
||||
Out << "@end\n";
|
||||
|
||||
// FIXME: implement the rest...
|
||||
}
|
||||
|
||||
void DeclPrinter::PrintObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *AID) {
|
||||
Out << "@compatibility_alias " << AID->getName()
|
||||
<< ' ' << AID->getClassInterface()->getName() << ";\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().getName();
|
||||
first = false;
|
||||
}
|
||||
if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_setter) {
|
||||
Out << (first ? ' ' : ',') << "setter = "
|
||||
<< PDecl->getSetterName().getName();
|
||||
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->getName();
|
||||
|
||||
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()->getName();
|
||||
if (PID->getPropertyIvarDecl())
|
||||
Out << "=" << PID->getPropertyIvarDecl()->getName();
|
||||
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 (ScopedDecl *SD = dyn_cast<ScopedDecl>(D)) {
|
||||
Out << "Read top-level variable decl: '" << SD->getName() << "'\n";
|
||||
} else if (ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(D)) {
|
||||
Out << "Read objc interface '" << OID->getName() << "'\n";
|
||||
} else if (ObjCProtocolDecl *OPD = dyn_cast<ObjCProtocolDecl>(D)) {
|
||||
Out << "Read objc protocol '" << OPD->getName() << "'\n";
|
||||
} else if (ObjCCategoryDecl *OCD = dyn_cast<ObjCCategoryDecl>(D)) {
|
||||
Out << "Read objc category '" << OCD->getName() << "'\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().getName()
|
||||
<< "'\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 {
|
||||
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(); }
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// 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();
|
||||
unsigned ID = SourceMgr.getMainFileID();
|
||||
assert (ID && "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);
|
||||
}
|
||||
|
||||
class LLVMCodeGenWriter : public ASTConsumer {
|
||||
llvm::OwningPtr<CodeGenerator> Gen;
|
||||
const std::string &InFile;
|
||||
const std::string &OutputFile;
|
||||
bool EmitBitcode;
|
||||
public:
|
||||
|
||||
LLVMCodeGenWriter(bool EmitBC, Diagnostic &Diags, const LangOptions &Features,
|
||||
const std::string& infile, const std::string& outfile,
|
||||
bool GenerateDebugInfo)
|
||||
: Gen(CreateLLVMCodeGen(Diags, Features, infile, GenerateDebugInfo)),
|
||||
InFile(infile), OutputFile(outfile), EmitBitcode(EmitBC) {}
|
||||
|
||||
virtual void Initialize(ASTContext &Context) {
|
||||
Gen->Initialize(Context);
|
||||
}
|
||||
|
||||
virtual void InitializeTU(TranslationUnit& TU) {
|
||||
Gen->InitializeTU(TU);
|
||||
}
|
||||
|
||||
virtual void HandleTopLevelDecl(Decl *D) {
|
||||
Gen->HandleTopLevelDecl(D);
|
||||
}
|
||||
|
||||
virtual void HandleTranslationUnit(TranslationUnit& TU) {
|
||||
Gen->HandleTranslationUnit(TU);
|
||||
}
|
||||
|
||||
virtual void HandleTagDeclDefinition(TagDecl *D) {
|
||||
Gen->HandleTagDeclDefinition(D);
|
||||
}
|
||||
|
||||
virtual ~LLVMCodeGenWriter() {
|
||||
llvm::OwningPtr<llvm::Module> CodeGenModule(Gen->ReleaseModule());
|
||||
|
||||
if (!CodeGenModule)
|
||||
return;
|
||||
|
||||
std::ostream *Out;
|
||||
|
||||
if (OutputFile == "-") {
|
||||
Out = llvm::cout.stream();
|
||||
} else if (!OutputFile.empty()) {
|
||||
Out = new std::ofstream(OutputFile.c_str(),
|
||||
std::ios_base::binary|std::ios_base::out);
|
||||
} else if (InFile == "-") {
|
||||
Out = llvm::cout.stream();
|
||||
} else {
|
||||
llvm::sys::Path Path(InFile);
|
||||
Path.eraseSuffix();
|
||||
if (!EmitBitcode)
|
||||
Path.appendSuffix("ll");
|
||||
else
|
||||
Path.appendSuffix("bc");
|
||||
|
||||
Out = new std::ofstream(Path.toString().c_str(),
|
||||
std::ios_base::binary|std::ios_base::out);
|
||||
}
|
||||
|
||||
if (!EmitBitcode)
|
||||
*Out << *CodeGenModule.get();
|
||||
else
|
||||
llvm::WriteBitcodeToFile(CodeGenModule.get(), *Out);
|
||||
|
||||
if (Out != llvm::cout.stream())
|
||||
delete Out;
|
||||
}
|
||||
};
|
||||
|
||||
ASTConsumer *clang::CreateLLVMCodeGenWriter(bool EmitBC, Diagnostic &Diags,
|
||||
const LangOptions &Features,
|
||||
const std::string& InFile,
|
||||
const std::string& OutFile,
|
||||
bool GenerateDebugInfo) {
|
||||
|
||||
return new LLVMCodeGenWriter(EmitBC, Diags, Features, InFile, OutFile,
|
||||
GenerateDebugInfo);
|
||||
}
|
||||
@@ -1,69 +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;
|
||||
struct LangOptions;
|
||||
class Preprocessor;
|
||||
class PreprocessorFactory;
|
||||
|
||||
ASTConsumer *CreateASTPrinter(llvm::raw_ostream* OS = NULL);
|
||||
|
||||
ASTConsumer *CreateASTDumper();
|
||||
|
||||
ASTConsumer *CreateASTViewer();
|
||||
|
||||
ASTConsumer *CreateCodeRewriterTest(const std::string& InFile,
|
||||
const std::string& OutFile,
|
||||
Diagnostic &Diags,
|
||||
const LangOptions &LOpts);
|
||||
|
||||
ASTConsumer *CreateLLVMCodeGenWriter(bool EmitBC, Diagnostic &Diags,
|
||||
const LangOptions &Features,
|
||||
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);
|
||||
} // end clang namespace
|
||||
|
||||
#include "AnalysisConsumer.h"
|
||||
|
||||
#endif
|
||||
@@ -1,46 +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.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
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)
|
||||
|
||||
#undef ANALYSIS
|
||||
@@ -1,575 +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/HTMLDiagnostics.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/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();
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// 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;
|
||||
|
||||
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;
|
||||
|
||||
AnalysisConsumer(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)
|
||||
: VisGraphviz(visgraphviz), VisUbigraph(visubi), TrimGraph(trim),
|
||||
LOpts(lopts), Diags(diags),
|
||||
Ctx(0), PP(pp), PPF(ppf),
|
||||
HTMLDir(htmldir),
|
||||
FName(fname),
|
||||
AnalyzeAll(analyzeAll) {}
|
||||
|
||||
void addCodeAction(CodeAction action) {
|
||||
FunctionActions.push_back(action);
|
||||
ObjCMethodActions.push_back(action);
|
||||
}
|
||||
|
||||
void addObjCImplementationAction(CodeAction action) {
|
||||
ObjCImplementationActions.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;
|
||||
AnalysisConsumer& C;
|
||||
bool DisplayedFunction;
|
||||
|
||||
llvm::OwningPtr<CFG> cfg;
|
||||
llvm::OwningPtr<LiveVariables> liveness;
|
||||
llvm::OwningPtr<ParentMap> PM;
|
||||
|
||||
public:
|
||||
AnalysisManager(AnalysisConsumer& c, Decl* d, Stmt* b)
|
||||
: D(d), Body(b), C(c), DisplayedFunction(false) {}
|
||||
|
||||
|
||||
Decl* getCodeDecl() const { return D; }
|
||||
Stmt* getBody() const { return Body; }
|
||||
|
||||
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())
|
||||
C.PD.reset(CreateHTMLDiagnosticClient(C.HTMLDir, C.PP, C.PPF));
|
||||
|
||||
return C.PD.get();
|
||||
}
|
||||
|
||||
virtual LiveVariables* getLiveVariables() {
|
||||
if (!liveness) {
|
||||
CFG* c = getCFG();
|
||||
if (!c) return 0;
|
||||
|
||||
liveness.reset(new LiveVariables(*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;
|
||||
|
||||
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(getCodeDecl())) {
|
||||
llvm::cout << "ANALYZE: "
|
||||
<< getContext().getSourceManager().getSourceName(FD->getLocation())
|
||||
<< ' '
|
||||
<< FD->getIdentifier()->getName()
|
||||
<< '\n';
|
||||
}
|
||||
else if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(getCodeDecl())) {
|
||||
llvm::cout << "ANALYZE (ObjC Method): "
|
||||
<< getContext().getSourceManager().getSourceName(MD->getLocation())
|
||||
<< " '"
|
||||
<< MD->getSelector().getName() << "'\n";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // 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().getName())
|
||||
return;
|
||||
|
||||
Stmt* Body = MD->getBody();
|
||||
if (Body) HandleCode(MD, Body, ObjCMethodActions);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void AnalysisConsumer::HandleTranslationUnit(TranslationUnit& TU) {
|
||||
|
||||
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;
|
||||
|
||||
SourceLocation Loc = D->getLocation();
|
||||
|
||||
// Only run actions on declarations defined in actual source.
|
||||
if (!Loc.isFileID())
|
||||
return;
|
||||
|
||||
// Don't run the actions on declarations in header files unless
|
||||
// otherwise specified.
|
||||
if (!AnalyzeAll && !Ctx->getSourceManager().isFromMainFile(Loc))
|
||||
return;
|
||||
|
||||
// Create an AnalysisManager that will manage the state for analyzing
|
||||
// this method/function.
|
||||
AnalysisManager mgr(*this, D, Body);
|
||||
|
||||
// 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);
|
||||
|
||||
// Construct the analysis engine.
|
||||
LiveVariables* L = mgr.getLiveVariables();
|
||||
if (!L) return;
|
||||
|
||||
// Display progress.
|
||||
mgr.DisplayFunction();
|
||||
|
||||
GRExprEngine Eng(*mgr.getCFG(), *mgr.getCodeDecl(), mgr.getContext(), *L);
|
||||
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,
|
||||
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) {
|
||||
|
||||
llvm::OwningPtr<AnalysisConsumer>
|
||||
C(new AnalysisConsumer(diags, pp, ppf, lopts, fname, htmldir,
|
||||
VisGraphviz, VisUbi, trim, analyzeAll));
|
||||
|
||||
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(), 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,37 +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
|
||||
};
|
||||
|
||||
ASTConsumer* CreateAnalysisConsumer(Analyses* Beg, Analyses* End,
|
||||
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);
|
||||
} // end clang namespace
|
||||
|
||||
#endif
|
||||
@@ -1,267 +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;
|
||||
|
||||
// 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.
|
||||
|
||||
static const char * const ExpectedErrStr = "expected-error";
|
||||
static const char * const ExpectedWarnStr = "expected-warning";
|
||||
static const char * const ExpectedNoteStr = "expected-note";
|
||||
|
||||
/// 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 std::string &Comment,
|
||||
DiagList &ExpectedDiags,
|
||||
SourceManager &SourceMgr,
|
||||
SourceLocation Pos,
|
||||
const char * const ExpectedStr) {
|
||||
// Find all expected diagnostics
|
||||
typedef std::string::size_type size_type;
|
||||
size_type ColNo = 0;
|
||||
|
||||
for (;;) {
|
||||
ColNo = Comment.find(ExpectedStr, ColNo);
|
||||
if (ColNo == std::string::npos) break;
|
||||
|
||||
size_type OpenDiag = Comment.find("{{", ColNo);
|
||||
|
||||
if (OpenDiag == std::string::npos) {
|
||||
fprintf(stderr,
|
||||
"oops:%d: Cannot find beginning of expected error string\n",
|
||||
SourceMgr.getLogicalLineNumber(Pos));
|
||||
break;
|
||||
}
|
||||
|
||||
OpenDiag += 2;
|
||||
size_type CloseDiag = Comment.find("}}", OpenDiag);
|
||||
|
||||
if (CloseDiag == std::string::npos) {
|
||||
fprintf(stderr,
|
||||
"oops:%d: Cannot find end of expected error string\n",
|
||||
SourceMgr.getLogicalLineNumber(Pos));
|
||||
break;
|
||||
}
|
||||
|
||||
std::string Msg(Comment.substr(OpenDiag, CloseDiag - OpenDiag));
|
||||
ExpectedDiags.push_back(std::make_pair(Pos, Msg));
|
||||
ColNo = CloseDiag + 2;
|
||||
}
|
||||
}
|
||||
|
||||
/// 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) {
|
||||
// Return comments as tokens, this is how we find expected diagnostics.
|
||||
PP.SetCommentRetentionState(true, true);
|
||||
|
||||
// Enter the cave.
|
||||
PP.EnterMainSourceFile();
|
||||
|
||||
// Turn off all warnings from relexing or preprocessing.
|
||||
PP.getDiagnostics().setWarnOnExtensions(false);
|
||||
PP.getDiagnostics().setErrorOnExtensions(false);
|
||||
for (unsigned i = 0; i != diag::NUM_BUILTIN_DIAGNOSTICS; ++i)
|
||||
if (PP.getDiagnostics().isBuiltinNoteWarningOrExtension((diag::kind)i))
|
||||
PP.getDiagnostics().setDiagnosticMapping((diag::kind)i, diag::MAP_IGNORE);
|
||||
|
||||
Token Tok;
|
||||
do {
|
||||
PP.Lex(Tok);
|
||||
|
||||
if (Tok.is(tok::comment)) {
|
||||
std::string Comment = PP.getSpelling(Tok);
|
||||
|
||||
// Find all expected errors
|
||||
FindDiagnostics(Comment, ExpectedErrors,PP.getSourceManager(),
|
||||
Tok.getLocation(), ExpectedErrStr);
|
||||
|
||||
// Find all expected warnings
|
||||
FindDiagnostics(Comment, ExpectedWarnings, PP.getSourceManager(),
|
||||
Tok.getLocation(), ExpectedWarnStr);
|
||||
|
||||
// Find all expected notes
|
||||
FindDiagnostics(Comment, ExpectedNotes, PP.getSourceManager(),
|
||||
Tok.getLocation(), ExpectedNoteStr);
|
||||
}
|
||||
} while (Tok.isNot(tok::eof));
|
||||
|
||||
PP.SetCommentRetentionState(false, false);
|
||||
}
|
||||
|
||||
/// 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.getLogicalLineNumber(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.getLogicalLineNumber(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.getLogicalLineNumber(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;
|
||||
}
|
||||
|
||||
|
||||
/// CheckASTConsumer - Implement diagnostic checking for AST consumers.
|
||||
bool clang::CheckASTConsumer(Preprocessor &PP, ASTConsumer* C) {
|
||||
|
||||
// Parse the AST and run the consumer, ultimately deleting C.
|
||||
ParseAST(PP, C);
|
||||
return CheckDiagnostics(PP);
|
||||
}
|
||||
|
||||
/// 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.
|
||||
unsigned FileID = R.getSourceMgr().getMainFileID();
|
||||
const FileEntry* Entry = R.getSourceMgr().getFileEntryForID(FileID);
|
||||
|
||||
html::AddLineNumbers(R, FileID);
|
||||
html::AddHeaderFooterInternalBuiltinCSS(R, FileID, 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, FileID, *PP);
|
||||
if (PPF) html::HighlightMacros(R, FileID, *PP);
|
||||
html::EscapeText(R, FileID, 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(FileID);
|
||||
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,12 +0,0 @@
|
||||
LEVEL = ../../..
|
||||
CPPFLAGS += -I$(PROJ_SRC_DIR)/../include
|
||||
CXXFLAGS = -fno-rtti
|
||||
|
||||
TOOLNAME = clang
|
||||
USEDLIBS = clangCodeGen.a clangAnalysis.a clangRewrite.a clangSema.a \
|
||||
clangDriver.a clangAST.a clangParse.a clangLex.a clangBasic.a \
|
||||
LLVMCore.a LLVMSupport.a LLVMSystem.a \
|
||||
LLVMBitWriter.a LLVMBitReader.a LLVMCodeGen.a LLVMAnalysis.a \
|
||||
LLVMTarget.a
|
||||
|
||||
include $(LEVEL)/Makefile.common
|
||||
@@ -1,572 +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(IdentifierTable &IT) : MinimalAction(IT) {}
|
||||
|
||||
// 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, ExprTy *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, StmtTy *Body) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual DeclTy *ActOnFileScopeAsmDecl(SourceLocation Loc, ExprTy *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;
|
||||
}
|
||||
|
||||
virtual DeclTy *ActOnLinkageSpec(SourceLocation Loc, SourceLocation LBrace,
|
||||
SourceLocation RBrace, const char *Lang,
|
||||
unsigned StrSize, DeclTy *D) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
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, IdentifierInfo *Name,
|
||||
SourceLocation NameLoc, AttributeList *Attr) {
|
||||
// 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, SourceLocation DeclStart,
|
||||
IdentifierInfo *ClassName,
|
||||
llvm::SmallVectorImpl<DeclTy*> &Decls) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
}
|
||||
|
||||
virtual DeclTy *ActOnField(Scope *S, 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 StmtResult ActOnNullStmt(SourceLocation SemiLoc) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual StmtResult ActOnCompoundStmt(SourceLocation L, SourceLocation R,
|
||||
StmtTy **Elts, unsigned NumElts,
|
||||
bool isStmtExpr) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return 0;
|
||||
}
|
||||
virtual StmtResult ActOnDeclStmt(DeclTy *Decl, SourceLocation StartLoc,
|
||||
SourceLocation EndLoc) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual StmtResult ActOnExprStmt(ExprTy *Expr) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return StmtResult(Expr);
|
||||
}
|
||||
|
||||
/// ActOnCaseStmt - Note that this handles the GNU 'case 1 ... 4' extension,
|
||||
/// which can specify an RHS value.
|
||||
virtual StmtResult ActOnCaseStmt(SourceLocation CaseLoc, ExprTy *LHSVal,
|
||||
SourceLocation DotDotDotLoc, ExprTy *RHSVal,
|
||||
SourceLocation ColonLoc, StmtTy *SubStmt) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return 0;
|
||||
}
|
||||
virtual StmtResult ActOnDefaultStmt(SourceLocation DefaultLoc,
|
||||
SourceLocation ColonLoc, StmtTy *SubStmt,
|
||||
Scope *CurScope){
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual StmtResult ActOnLabelStmt(SourceLocation IdentLoc, IdentifierInfo *II,
|
||||
SourceLocation ColonLoc, StmtTy *SubStmt) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual StmtResult ActOnIfStmt(SourceLocation IfLoc, ExprTy *CondVal,
|
||||
StmtTy *ThenVal, SourceLocation ElseLoc,
|
||||
StmtTy *ElseVal) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual StmtResult ActOnStartOfSwitchStmt(ExprTy *Cond) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual StmtResult ActOnFinishSwitchStmt(SourceLocation SwitchLoc,
|
||||
StmtTy *Switch, ExprTy *Body) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual StmtResult ActOnWhileStmt(SourceLocation WhileLoc, ExprTy *Cond,
|
||||
StmtTy *Body) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return 0;
|
||||
}
|
||||
virtual StmtResult ActOnDoStmt(SourceLocation DoLoc, StmtTy *Body,
|
||||
SourceLocation WhileLoc, ExprTy *Cond) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return 0;
|
||||
}
|
||||
virtual StmtResult ActOnForStmt(SourceLocation ForLoc,
|
||||
SourceLocation LParenLoc,
|
||||
StmtTy *First, ExprTy *Second, ExprTy *Third,
|
||||
SourceLocation RParenLoc, StmtTy *Body) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return 0;
|
||||
}
|
||||
virtual StmtResult ActOnObjCForCollectionStmt(SourceLocation ForColLoc,
|
||||
SourceLocation LParenLoc,
|
||||
StmtTy *First, ExprTy *Second,
|
||||
SourceLocation RParenLoc, StmtTy *Body) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return 0;
|
||||
}
|
||||
virtual StmtResult ActOnGotoStmt(SourceLocation GotoLoc,
|
||||
SourceLocation LabelLoc,
|
||||
IdentifierInfo *LabelII) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return 0;
|
||||
}
|
||||
virtual StmtResult ActOnIndirectGotoStmt(SourceLocation GotoLoc,
|
||||
SourceLocation StarLoc,
|
||||
ExprTy *DestExp) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return 0;
|
||||
}
|
||||
virtual StmtResult ActOnContinueStmt(SourceLocation ContinueLoc,
|
||||
Scope *CurScope) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return 0;
|
||||
}
|
||||
virtual StmtResult ActOnBreakStmt(SourceLocation GotoLoc, Scope *CurScope) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return 0;
|
||||
}
|
||||
virtual StmtResult ActOnReturnStmt(SourceLocation ReturnLoc,
|
||||
ExprTy *RetValExp) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return 0;
|
||||
}
|
||||
virtual StmtResult ActOnAsmStmt(SourceLocation AsmLoc,
|
||||
bool IsSimple,
|
||||
bool IsVolatile,
|
||||
unsigned NumOutputs,
|
||||
unsigned NumInputs,
|
||||
std::string *Names,
|
||||
ExprTy **Constraints,
|
||||
ExprTy **Exprs,
|
||||
ExprTy *AsmString,
|
||||
unsigned NumClobbers,
|
||||
ExprTy **Clobbers,
|
||||
SourceLocation RParenLoc) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Objective-c statements
|
||||
virtual StmtResult ActOnObjCAtCatchStmt(SourceLocation AtLoc,
|
||||
SourceLocation RParen, StmtTy *Parm,
|
||||
StmtTy *Body, StmtTy *CatchList) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual StmtResult ActOnObjCAtFinallyStmt(SourceLocation AtLoc,
|
||||
StmtTy *Body) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual StmtResult ActOnObjCAtTryStmt(SourceLocation AtLoc,
|
||||
StmtTy *Try,
|
||||
StmtTy *Catch, StmtTy *Finally) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual StmtResult ActOnObjCAtThrowStmt(SourceLocation AtLoc,
|
||||
StmtTy *Throw) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual StmtResult ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc,
|
||||
ExprTy *SynchExpr,
|
||||
StmtTy *SynchBody) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// 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 ExprResult ActOnIdentifierExpr(Scope *S, SourceLocation Loc,
|
||||
IdentifierInfo &II,
|
||||
bool HasTrailingLParen) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual ExprResult ActOnPredefinedExpr(SourceLocation Loc,
|
||||
tok::TokenKind Kind) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual ExprResult ActOnCharacterConstant(const Token &) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual ExprResult ActOnNumericConstant(const Token &) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// ActOnStringLiteral - The specified tokens were lexed as pasted string
|
||||
/// fragments (e.g. "foo" "bar" L"baz").
|
||||
virtual ExprResult ActOnStringLiteral(const Token *Toks, unsigned NumToks) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual ExprResult ActOnParenExpr(SourceLocation L, SourceLocation R,
|
||||
ExprTy *Val) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return Val; // Default impl returns operand.
|
||||
}
|
||||
|
||||
// Postfix Expressions.
|
||||
virtual ExprResult ActOnPostfixUnaryOp(SourceLocation OpLoc,
|
||||
tok::TokenKind Kind, ExprTy *Input) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return 0;
|
||||
}
|
||||
virtual ExprResult ActOnArraySubscriptExpr(ExprTy *Base, SourceLocation LLoc,
|
||||
ExprTy *Idx, SourceLocation RLoc) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return 0;
|
||||
}
|
||||
virtual ExprResult ActOnMemberReferenceExpr(ExprTy *Base,SourceLocation OpLoc,
|
||||
tok::TokenKind OpKind,
|
||||
SourceLocation MemberLoc,
|
||||
IdentifierInfo &Member) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// ActOnCallExpr - Handle a call to Fn with the specified array of arguments.
|
||||
/// This provides the location of the left/right parens and a list of comma
|
||||
/// locations. There are guaranteed to be one fewer commas than arguments,
|
||||
/// unless there are zero arguments.
|
||||
virtual ExprResult ActOnCallExpr(ExprTy *Fn, SourceLocation LParenLoc,
|
||||
ExprTy **Args, unsigned NumArgs,
|
||||
SourceLocation *CommaLocs,
|
||||
SourceLocation RParenLoc) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Unary Operators. 'Tok' is the token for the operator.
|
||||
virtual ExprResult ActOnUnaryOp(SourceLocation OpLoc, tok::TokenKind Op,
|
||||
ExprTy *Input) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return 0;
|
||||
}
|
||||
virtual ExprResult
|
||||
ActOnSizeOfAlignOfTypeExpr(SourceLocation OpLoc, bool isSizeof,
|
||||
SourceLocation LParenLoc, TypeTy *Ty,
|
||||
SourceLocation RParenLoc) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual ExprResult ActOnCompoundLiteral(SourceLocation LParen, TypeTy *Ty,
|
||||
SourceLocation RParen, ExprTy *Op) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return 0;
|
||||
}
|
||||
virtual ExprResult ActOnInitList(SourceLocation LParenLoc,
|
||||
ExprTy **InitList, unsigned NumInit,
|
||||
SourceLocation RParenLoc) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return 0;
|
||||
}
|
||||
virtual ExprResult ActOnCastExpr(SourceLocation LParenLoc, TypeTy *Ty,
|
||||
SourceLocation RParenLoc, ExprTy *Op) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual ExprResult ActOnBinOp(SourceLocation TokLoc, tok::TokenKind Kind,
|
||||
ExprTy *LHS, ExprTy *RHS) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// ActOnConditionalOp - Parse a ?: operation. Note that 'LHS' may be null
|
||||
/// in the case of a the GNU conditional expr extension.
|
||||
virtual ExprResult ActOnConditionalOp(SourceLocation QuestionLoc,
|
||||
SourceLocation ColonLoc,
|
||||
ExprTy *Cond, ExprTy *LHS, ExprTy *RHS){
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
//===---------------------- 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(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(IdentifierTable &IT) {
|
||||
return new ParserPrintActions(IT);
|
||||
}
|
||||
@@ -1,551 +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::Characteristic_t 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::Characteristic_t FileType);
|
||||
virtual void Ident(SourceLocation Loc, 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().getLogicalLineNumber(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; // Phys line moved, but logical 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::Characteristic_t 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) {
|
||||
MoveToLine(SourceMgr.getIncludeLoc(Loc));
|
||||
} 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.getLogicalLoc(Loc);
|
||||
CurLine = SourceMgr.getLineNumber(Loc);
|
||||
|
||||
if (DisableLineMarkers) return;
|
||||
|
||||
CurFilename.clear();
|
||||
CurFilename += SourceMgr.getSourceName(Loc);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/// HandleIdent - 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;
|
||||
}
|
||||
|
||||
/// 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 physical lines, not logical 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.getLogicalColumnNumber(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.getPhysicalLoc(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.getPhysicalLoc(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()) {
|
||||
SourceManager &SrcMgr = PP.getSourceManager();
|
||||
FirstChar =
|
||||
*SrcMgr.getCharacterData(SrcMgr.getPhysicalLoc(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 == '.' || FirstChar == '*' || isdigit(FirstChar);
|
||||
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 == ':';
|
||||
case tok::colon: // ::, :>
|
||||
return FirstChar == ':' || FirstChar == '>';
|
||||
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(), 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.getSourceName(Tok.getLocation()), "<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()) {
|
||||
const char *Str = II->getName();
|
||||
unsigned Len = Tok.needsCleaning() ? strlen(Str) : Tok.getLength();
|
||||
OS.write(Str, Len);
|
||||
} 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,238 +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();
|
||||
std::pair<const char*,const char*> File =SM.getBufferData(SM.getMainFileID());
|
||||
|
||||
// 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(SourceLocation::getFileLoc(SM.getMainFileID(), 0),
|
||||
PP.getLangOptions(), File.first, File.second);
|
||||
|
||||
// Switch on comment lexing because we really do want them.
|
||||
RawLex.SetCommentRetentionState(true);
|
||||
|
||||
Token RawTok;
|
||||
do {
|
||||
RawLex.LexRawToken(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.getLogicalLoc(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.getFullFilePos(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.getFullFilePos(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.getFullFilePos(PPLoc);
|
||||
unsigned RawOffs = SM.getFullFilePos(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.getFullFilePos(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.getLogicalLoc(PPTok.getLocation());
|
||||
PPOffs = SM.getFullFilePos(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(), 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(), 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,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(), 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(), 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,52 +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);
|
||||
|
||||
/// CreatePrintParserActionsAction - Return the actions implementation that
|
||||
/// implements the -parse-print-callbacks option.
|
||||
MinimalAction *CreatePrintParserActionsAction(IdentifierTable &);
|
||||
|
||||
/// EmitLLVMFromASTs - Implement -emit-llvm, which generates llvm IR from C.
|
||||
void EmitLLVMFromASTs(Preprocessor &PP, bool PrintStats);
|
||||
|
||||
/// CheckASTConsumer - Implement diagnostic checking for AST consumers.
|
||||
bool CheckASTConsumer(Preprocessor &PP, ASTConsumer* C);
|
||||
|
||||
/// CheckDiagnostics - Gather the expected diagnostics and check them.
|
||||
bool CheckDiagnostics(Preprocessor &PP);
|
||||
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
@@ -1,2 +0,0 @@
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
@@ -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,15 +0,0 @@
|
||||
LEVEL = ../..
|
||||
DIRS := lib Driver docs
|
||||
|
||||
include $(LEVEL)/Makefile.common
|
||||
|
||||
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:
|
||||
136
clang/NOTES.txt
136
clang/NOTES.txt
@@ -1,136 +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.
|
||||
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
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.
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
TODO: New language feature: Configuration queries:
|
||||
- Instead of #ifdef __POWERPC__, use "if (strcmp(`cpu`, __POWERPC__))", or
|
||||
some other, better, syntax.
|
||||
- Use it to increase the number of "architecture-clean" #import'd files,
|
||||
allowing a single index to be used for all fat slices.
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
// 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
|
||||
};
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
199
clang/README.txt
199
clang/README.txt
@@ -1,199 +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,34 +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.
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,624 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>"clang" CFE Internals Manual</title>
|
||||
<link type="text/css" rel="stylesheet" href="../menu.css" />
|
||||
<link type="text/css" rel="stylesheet" href="../content.css" />
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!--#include virtual="../menu.html.incl"-->
|
||||
|
||||
<div id="content">
|
||||
|
||||
<h1>"clang" CFE Internals Manual</h1>
|
||||
|
||||
<ul>
|
||||
<li><a href="#intro">Introduction</a></li>
|
||||
<li><a href="#libsystem">LLVM System and Support Libraries</a></li>
|
||||
<li><a href="#libbasic">The clang 'Basic' Library</a>
|
||||
<ul>
|
||||
<li><a href="#SourceLocation">The SourceLocation and SourceManager
|
||||
classes</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#liblex">The Lexer and Preprocessor Library</a>
|
||||
<ul>
|
||||
<li><a href="#Token">The Token class</a></li>
|
||||
<li><a href="#Lexer">The Lexer class</a></li>
|
||||
<li><a href="#TokenLexer">The TokenLexer class</a></li>
|
||||
<li><a href="#MultipleIncludeOpt">The MultipleIncludeOpt class</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#libparse">The Parser Library</a>
|
||||
<ul>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#libast">The AST Library</a>
|
||||
<ul>
|
||||
<li><a href="#Type">The Type class and its subclasses</a></li>
|
||||
<li><a href="#QualType">The QualType class</a></li>
|
||||
<li><a href="#CFG">The CFG class</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="intro">Introduction</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>This document describes some of the more important APIs and internal design
|
||||
decisions made in the clang C front-end. The purpose of this document is to
|
||||
both capture some of this high level information and also describe some of the
|
||||
design decisions behind it. This is meant for people interested in hacking on
|
||||
clang, not for end-users. The description below is categorized by
|
||||
libraries, and does not describe any of the clients of the libraries.</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="libsystem">LLVM System and Support Libraries</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>The LLVM libsystem library provides the basic clang system abstraction layer,
|
||||
which is used for file system access. The LLVM libsupport library provides many
|
||||
underlying libraries and <a
|
||||
href="http://llvm.org/docs/ProgrammersManual.html">data-structures</a>,
|
||||
including command line option
|
||||
processing and various containers.</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="libbasic">The clang 'Basic' Library</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>This library certainly needs a better name. The 'basic' library contains a
|
||||
number of low-level utilities for tracking and manipulating source buffers,
|
||||
locations within the source buffers, diagnostics, tokens, target abstraction,
|
||||
and information about the subset of the language being compiled for.</p>
|
||||
|
||||
<p>Part of this infrastructure is specific to C (such as the TargetInfo class),
|
||||
other parts could be reused for other non-C-based languages (SourceLocation,
|
||||
SourceManager, Diagnostics, FileManager). When and if there is future demand
|
||||
we can figure out if it makes sense to introduce a new library, move the general
|
||||
classes somewhere else, or introduce some other solution.</p>
|
||||
|
||||
<p>We describe the roles of these classes in order of their dependencies.</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h3 id="SourceLocation">The SourceLocation and SourceManager classes</h3>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>Strangely enough, the SourceLocation class represents a location within the
|
||||
source code of the program. Important design points include:</p>
|
||||
|
||||
<ol>
|
||||
<li>sizeof(SourceLocation) must be extremely small, as these are embedded into
|
||||
many AST nodes and are passed around often. Currently it is 32 bits.</li>
|
||||
<li>SourceLocation must be a simple value object that can be efficiently
|
||||
copied.</li>
|
||||
<li>We should be able to represent a source location for any byte of any input
|
||||
file. This includes in the middle of tokens, in whitespace, in trigraphs,
|
||||
etc.</li>
|
||||
<li>A SourceLocation must encode the current #include stack that was active when
|
||||
the location was processed. For example, if the location corresponds to a
|
||||
token, it should contain the set of #includes active when the token was
|
||||
lexed. This allows us to print the #include stack for a diagnostic.</li>
|
||||
<li>SourceLocation must be able to describe macro expansions, capturing both
|
||||
the ultimate instantiation point and the source of the original character
|
||||
data.</li>
|
||||
</ol>
|
||||
|
||||
<p>In practice, the SourceLocation works together with the SourceManager class
|
||||
to encode two pieces of information about a location: it's physical location
|
||||
and it's virtual location. For most tokens, these will be the same. However,
|
||||
for a macro expansion (or tokens that came from a _Pragma directive) these will
|
||||
describe the location of the characters corresponding to the token and the
|
||||
location where the token was used (i.e. the macro instantiation point or the
|
||||
location of the _Pragma itself).</p>
|
||||
|
||||
<p>For efficiency, we only track one level of macro instantions: if a token was
|
||||
produced by multiple instantiations, we only track the source and ultimate
|
||||
destination. Though we could track the intermediate instantiation points, this
|
||||
would require extra bookkeeping and no known client would benefit substantially
|
||||
from this.</p>
|
||||
|
||||
<p>The clang front-end inherently depends on the location of a token being
|
||||
tracked correctly. If it is ever incorrect, the front-end may get confused and
|
||||
die. The reason for this is that the notion of the 'spelling' of a Token in
|
||||
clang depends on being able to find the original input characters for the token.
|
||||
This concept maps directly to the "physical" location for the token.</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="liblex">The Lexer and Preprocessor Library</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>The Lexer library contains several tightly-connected classes that are involved
|
||||
with the nasty process of lexing and preprocessing C source code. The main
|
||||
interface to this library for outside clients is the large <a
|
||||
href="#Preprocessor">Preprocessor</a> class.
|
||||
It contains the various pieces of state that are required to coherently read
|
||||
tokens out of a translation unit.</p>
|
||||
|
||||
<p>The core interface to the Preprocessor object (once it is set up) is the
|
||||
Preprocessor::Lex method, which returns the next <a href="#Token">Token</a> from
|
||||
the preprocessor stream. There are two types of token providers that the
|
||||
preprocessor is capable of reading from: a buffer lexer (provided by the <a
|
||||
href="#Lexer">Lexer</a> class) and a buffered token stream (provided by the <a
|
||||
href="#TokenLexer">TokenLexer</a> class).
|
||||
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h3 id="Token">The Token class</h3>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>The Token class is used to represent a single lexed token. Tokens are
|
||||
intended to be used by the lexer/preprocess and parser libraries, but are not
|
||||
intended to live beyond them (for example, they should not live in the ASTs).<p>
|
||||
|
||||
<p>Tokens most often live on the stack (or some other location that is efficient
|
||||
to access) as the parser is running, but occasionally do get buffered up. For
|
||||
example, macro definitions are stored as a series of tokens, and the C++
|
||||
front-end will eventually need to buffer tokens up for tentative parsing and
|
||||
various pieces of look-ahead. As such, the size of a Token matter. On a 32-bit
|
||||
system, sizeof(Token) is currently 16 bytes.</p>
|
||||
|
||||
<p>Tokens contain the following information:</p>
|
||||
|
||||
<ul>
|
||||
<li><b>A SourceLocation</b> - This indicates the location of the start of the
|
||||
token.</li>
|
||||
|
||||
<li><b>A length</b> - This stores the length of the token as stored in the
|
||||
SourceBuffer. For tokens that include them, this length includes trigraphs and
|
||||
escaped newlines which are ignored by later phases of the compiler. By pointing
|
||||
into the original source buffer, it is always possible to get the original
|
||||
spelling of a token completely accurately.</li>
|
||||
|
||||
<li><b>IdentifierInfo</b> - If a token takes the form of an identifier, and if
|
||||
identifier lookup was enabled when the token was lexed (e.g. the lexer was not
|
||||
reading in 'raw' mode) this contains a pointer to the unique hash value for the
|
||||
identifier. Because the lookup happens before keyword identification, this
|
||||
field is set even for language keywords like 'for'.</li>
|
||||
|
||||
<li><b>TokenKind</b> - This indicates the kind of token as classified by the
|
||||
lexer. This includes things like <tt>tok::starequal</tt> (for the "*="
|
||||
operator), <tt>tok::ampamp</tt> for the "&&" token, and keyword values
|
||||
(e.g. <tt>tok::kw_for</tt>) for identifiers that correspond to keywords. Note
|
||||
that some tokens can be spelled multiple ways. For example, C++ supports
|
||||
"operator keywords", where things like "and" are treated exactly like the
|
||||
"&&" operator. In these cases, the kind value is set to
|
||||
<tt>tok::ampamp</tt>, which is good for the parser, which doesn't have to
|
||||
consider both forms. For something that cares about which form is used (e.g.
|
||||
the preprocessor 'stringize' operator) the spelling indicates the original
|
||||
form.</li>
|
||||
|
||||
<li><b>Flags</b> - There are currently four flags tracked by the
|
||||
lexer/preprocessor system on a per-token basis:
|
||||
|
||||
<ol>
|
||||
<li><b>StartOfLine</b> - This was the first token that occurred on its input
|
||||
source line.</li>
|
||||
<li><b>LeadingSpace</b> - There was a space character either immediately
|
||||
before the token or transitively before the token as it was expanded
|
||||
through a macro. The definition of this flag is very closely defined by
|
||||
the stringizing requirements of the preprocessor.</li>
|
||||
<li><b>DisableExpand</b> - This flag is used internally to the preprocessor to
|
||||
represent identifier tokens which have macro expansion disabled. This
|
||||
prevents them from being considered as candidates for macro expansion ever
|
||||
in the future.</li>
|
||||
<li><b>NeedsCleaning</b> - This flag is set if the original spelling for the
|
||||
token includes a trigraph or escaped newline. Since this is uncommon,
|
||||
many pieces of code can fast-path on tokens that did not need cleaning.
|
||||
</p>
|
||||
</ol>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>One interesting (and somewhat unusual) aspect of tokens is that they don't
|
||||
contain any semantic information about the lexed value. For example, if the
|
||||
token was a pp-number token, we do not represent the value of the number that
|
||||
was lexed (this is left for later pieces of code to decide). Additionally, the
|
||||
lexer library has no notion of typedef names vs variable names: both are
|
||||
returned as identifiers, and the parser is left to decide whether a specific
|
||||
identifier is a typedef or a variable (tracking this requires scope information
|
||||
among other things).</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h3 id="Lexer">The Lexer class</h3>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>The Lexer class provides the mechanics of lexing tokens out of a source
|
||||
buffer and deciding what they mean. The Lexer is complicated by the fact that
|
||||
it operates on raw buffers that have not had spelling eliminated (this is a
|
||||
necessity to get decent performance), but this is countered with careful coding
|
||||
as well as standard performance techniques (for example, the comment handling
|
||||
code is vectorized on X86 and PowerPC hosts).</p>
|
||||
|
||||
<p>The lexer has a couple of interesting modal features:</p>
|
||||
|
||||
<ul>
|
||||
<li>The lexer can operate in 'raw' mode. This mode has several features that
|
||||
make it possible to quickly lex the file (e.g. it stops identifier lookup,
|
||||
doesn't specially handle preprocessor tokens, handles EOF differently, etc).
|
||||
This mode is used for lexing within an "<tt>#if 0</tt>" block, for
|
||||
example.</li>
|
||||
<li>The lexer can capture and return comments as tokens. This is required to
|
||||
support the -C preprocessor mode, which passes comments through, and is
|
||||
used by the diagnostic checker to identifier expect-error annotations.</li>
|
||||
<li>The lexer can be in ParsingFilename mode, which happens when preprocessing
|
||||
after reading a #include directive. This mode changes the parsing of '<'
|
||||
to return an "angled string" instead of a bunch of tokens for each thing
|
||||
within the filename.</li>
|
||||
<li>When parsing a preprocessor directive (after "<tt>#</tt>") the
|
||||
ParsingPreprocessorDirective mode is entered. This changes the parser to
|
||||
return EOM at a newline.</li>
|
||||
<li>The Lexer uses a LangOptions object to know whether trigraphs are enabled,
|
||||
whether C++ or ObjC keywords are recognized, etc.</li>
|
||||
</ul>
|
||||
|
||||
<p>In addition to these modes, the lexer keeps track of a couple of other
|
||||
features that are local to a lexed buffer, which change as the buffer is
|
||||
lexed:</p>
|
||||
|
||||
<ul>
|
||||
<li>The Lexer uses BufferPtr to keep track of the current character being
|
||||
lexed.</li>
|
||||
<li>The Lexer uses IsAtStartOfLine to keep track of whether the next lexed token
|
||||
will start with its "start of line" bit set.</li>
|
||||
<li>The Lexer keeps track of the current #if directives that are active (which
|
||||
can be nested).</li>
|
||||
<li>The Lexer keeps track of an <a href="#MultipleIncludeOpt">
|
||||
MultipleIncludeOpt</a> object, which is used to
|
||||
detect whether the buffer uses the standard "<tt>#ifndef XX</tt> /
|
||||
<tt>#define XX</tt>" idiom to prevent multiple inclusion. If a buffer does,
|
||||
subsequent includes can be ignored if the XX macro is defined.</li>
|
||||
</ul>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h3 id="TokenLexer">The TokenLexer class</h3>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>The TokenLexer class is a token provider that returns tokens from a list
|
||||
of tokens that came from somewhere else. It typically used for two things: 1)
|
||||
returning tokens from a macro definition as it is being expanded 2) returning
|
||||
tokens from an arbitrary buffer of tokens. The later use is used by _Pragma and
|
||||
will most likely be used to handle unbounded look-ahead for the C++ parser.</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h3 id="MultipleIncludeOpt">The MultipleIncludeOpt class</h3>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>The MultipleIncludeOpt class implements a really simple little state machine
|
||||
that is used to detect the standard "<tt>#ifndef XX</tt> / <tt>#define XX</tt>"
|
||||
idiom that people typically use to prevent multiple inclusion of headers. If a
|
||||
buffer uses this idiom and is subsequently #include'd, the preprocessor can
|
||||
simply check to see whether the guarding condition is defined or not. If so,
|
||||
the preprocessor can completely ignore the include of the header.</p>
|
||||
|
||||
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="libparse">The Parser Library</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="libast">The AST Library</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h3 id="Type">The Type class and its subclasses</h3>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>The Type class (and its subclasses) are an important part of the AST. Types
|
||||
are accessed through the ASTContext class, which implicitly creates and uniques
|
||||
them as they are needed. Types have a couple of non-obvious features: 1) they
|
||||
do not capture type qualifiers like const or volatile (See
|
||||
<a href="#QualType">QualType</a>), and 2) they implicitly capture typedef
|
||||
information. Once created, types are immutable (unlike decls).</p>
|
||||
|
||||
<p>Typedefs in C make semantic analysis a bit more complex than it would
|
||||
be without them. The issue is that we want to capture typedef information
|
||||
and represent it in the AST perfectly, but the semantics of operations need to
|
||||
"see through" typedefs. For example, consider this code:</p>
|
||||
|
||||
<code>
|
||||
void func() {<br>
|
||||
typedef int foo;<br>
|
||||
foo X, *Y;<br>
|
||||
typedef foo* bar;<br>
|
||||
bar Z;<br>
|
||||
*X; <i>// error</i><br>
|
||||
**Y; <i>// error</i><br>
|
||||
**Z; <i>// error</i><br>
|
||||
}<br>
|
||||
</code>
|
||||
|
||||
<p>The code above is illegal, and thus we expect there to be diagnostics emitted
|
||||
on the annotated lines. In this example, we expect to get:</p>
|
||||
|
||||
<pre>
|
||||
<b>test.c:6:1: error: indirection requires pointer operand ('foo' invalid)</b>
|
||||
*X; // error
|
||||
<font color="blue">^~</font>
|
||||
<b>test.c:7:1: error: indirection requires pointer operand ('foo' invalid)</b>
|
||||
**Y; // error
|
||||
<font color="blue">^~~</font>
|
||||
<b>test.c:8:1: error: indirection requires pointer operand ('foo' invalid)</b>
|
||||
**Z; // error
|
||||
<font color="blue">^~~</font>
|
||||
</pre>
|
||||
|
||||
<p>While this example is somewhat silly, it illustrates the point: we want to
|
||||
retain typedef information where possible, so that we can emit errors about
|
||||
"<tt>std::string</tt>" instead of "<tt>std::basic_string<char, std:...</tt>".
|
||||
Doing this requires properly keeping typedef information (for example, the type
|
||||
of "X" is "foo", not "int"), and requires properly propagating it through the
|
||||
various operators (for example, the type of *Y is "foo", not "int"). In order
|
||||
to retain this information, the type of these expressions is an instance of the
|
||||
TypedefType class, which indicates that the type of these expressions is a
|
||||
typedef for foo.
|
||||
</p>
|
||||
|
||||
<p>Representing types like this is great for diagnostics, because the
|
||||
user-specified type is always immediately available. There are two problems
|
||||
with this: first, various semantic checks need to make judgements about the
|
||||
<em>actual structure</em> of a type, ignoring typdefs. Second, we need an
|
||||
efficient way to query whether two types are structurally identical to each
|
||||
other, ignoring typedefs. The solution to both of these problems is the idea of
|
||||
canonical types.</p>
|
||||
|
||||
<h4>Canonical Types</h4>
|
||||
|
||||
<p>Every instance of the Type class contains a canonical type pointer. For
|
||||
simple types with no typedefs involved (e.g. "<tt>int</tt>", "<tt>int*</tt>",
|
||||
"<tt>int**</tt>"), the type just points to itself. For types that have a
|
||||
typedef somewhere in their structure (e.g. "<tt>foo</tt>", "<tt>foo*</tt>",
|
||||
"<tt>foo**</tt>", "<tt>bar</tt>"), the canonical type pointer points to their
|
||||
structurally equivalent type without any typedefs (e.g. "<tt>int</tt>",
|
||||
"<tt>int*</tt>", "<tt>int**</tt>", and "<tt>int*</tt>" respectively).</p>
|
||||
|
||||
<p>This design provides a constant time operation (dereferencing the canonical
|
||||
type pointer) that gives us access to the structure of types. For example,
|
||||
we can trivially tell that "bar" and "foo*" are the same type by dereferencing
|
||||
their canonical type pointers and doing a pointer comparison (they both point
|
||||
to the single "<tt>int*</tt>" type).</p>
|
||||
|
||||
<p>Canonical types and typedef types bring up some complexities that must be
|
||||
carefully managed. Specifically, the "isa/cast/dyncast" operators generally
|
||||
shouldn't be used in code that is inspecting the AST. For example, when type
|
||||
checking the indirection operator (unary '*' on a pointer), the type checker
|
||||
must verify that the operand has a pointer type. It would not be correct to
|
||||
check that with "<tt>isa<PointerType>(SubExpr->getType())</tt>",
|
||||
because this predicate would fail if the subexpression had a typedef type.</p>
|
||||
|
||||
<p>The solution to this problem are a set of helper methods on Type, used to
|
||||
check their properties. In this case, it would be correct to use
|
||||
"<tt>SubExpr->getType()->isPointerType()</tt>" to do the check. This
|
||||
predicate will return true if the <em>canonical type is a pointer</em>, which is
|
||||
true any time the type is structurally a pointer type. The only hard part here
|
||||
is remembering not to use the <tt>isa/cast/dyncast</tt> operations.</p>
|
||||
|
||||
<p>The second problem we face is how to get access to the pointer type once we
|
||||
know it exists. To continue the example, the result type of the indirection
|
||||
operator is the pointee type of the subexpression. In order to determine the
|
||||
type, we need to get the instance of PointerType that best captures the typedef
|
||||
information in the program. If the type of the expression is literally a
|
||||
PointerType, we can return that, otherwise we have to dig through the
|
||||
typedefs to find the pointer type. For example, if the subexpression had type
|
||||
"<tt>foo*</tt>", we could return that type as the result. If the subexpression
|
||||
had type "<tt>bar</tt>", we want to return "<tt>foo*</tt>" (note that we do
|
||||
<em>not</em> want "<tt>int*</tt>"). In order to provide all of this, Type has
|
||||
a getAsPointerType() method that checks whether the type is structurally a
|
||||
PointerType and, if so, returns the best one. If not, it returns a null
|
||||
pointer.</p>
|
||||
|
||||
<p>This structure is somewhat mystical, but after meditating on it, it will
|
||||
make sense to you :).</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h3 id="QualType">The QualType class</h3>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>The QualType class is designed as a trivial value class that is small,
|
||||
passed by-value and is efficient to query. The idea of QualType is that it
|
||||
stores the type qualifiers (const, volatile, restrict) separately from the types
|
||||
themselves: QualType is conceptually a pair of "Type*" and bits for the type
|
||||
qualifiers.</p>
|
||||
|
||||
<p>By storing the type qualifiers as bits in the conceptual pair, it is
|
||||
extremely efficient to get the set of qualifiers on a QualType (just return the
|
||||
field of the pair), add a type qualifier (which is a trivial constant-time
|
||||
operation that sets a bit), and remove one or more type qualifiers (just return
|
||||
a QualType with the bitfield set to empty).</p>
|
||||
|
||||
<p>Further, because the bits are stored outside of the type itself, we do not
|
||||
need to create duplicates of types with different sets of qualifiers (i.e. there
|
||||
is only a single heap allocated "int" type: "const int" and "volatile const int"
|
||||
both point to the same heap allocated "int" type). This reduces the heap size
|
||||
used to represent bits and also means we do not have to consider qualifiers when
|
||||
uniquing types (<a href="#Type">Type</a> does not even contain qualifiers).</p>
|
||||
|
||||
<p>In practice, on hosts where it is safe, the 3 type qualifiers are stored in
|
||||
the low bit of the pointer to the Type object. This means that QualType is
|
||||
exactly the same size as a pointer, and this works fine on any system where
|
||||
malloc'd objects are at least 8 byte aligned.</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h3 id="CFG">The <tt>CFG</tt> class</h3>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>The <tt>CFG</tt> class is designed to represent a source-level
|
||||
control-flow graph for a single statement (<tt>Stmt*</tt>). Typically
|
||||
instances of <tt>CFG</tt> are constructed for function bodies (usually
|
||||
an instance of <tt>CompoundStmt</tt>), but can also be instantiated to
|
||||
represent the control-flow of any class that subclasses <tt>Stmt</tt>,
|
||||
which includes simple expressions. Control-flow graphs are especially
|
||||
useful for performing
|
||||
<a href="http://en.wikipedia.org/wiki/Data_flow_analysis#Sensitivities">flow-
|
||||
or path-sensitive</a> program analyses on a given function.</p>
|
||||
|
||||
<h4>Basic Blocks</h4>
|
||||
|
||||
<p>Concretely, an instance of <tt>CFG</tt> is a collection of basic
|
||||
blocks. Each basic block is an instance of <tt>CFGBlock</tt>, which
|
||||
simply contains an ordered sequence of <tt>Stmt*</tt> (each referring
|
||||
to statements in the AST). The ordering of statements within a block
|
||||
indicates unconditional flow of control from one statement to the
|
||||
next. <a href="#ConditionalControlFlow">Conditional control-flow</a>
|
||||
is represented using edges between basic blocks. The statements
|
||||
within a given <tt>CFGBlock</tt> can be traversed using
|
||||
the <tt>CFGBlock::*iterator</tt> interface.</p>
|
||||
|
||||
<p>
|
||||
A <tt>CFG</tt> object owns the instances of <tt>CFGBlock</tt> within
|
||||
the control-flow graph it represents. Each <tt>CFGBlock</tt> within a
|
||||
CFG is also uniquely numbered (accessible
|
||||
via <tt>CFGBlock::getBlockID()</tt>). Currently the number is
|
||||
based on the ordering the blocks were created, but no assumptions
|
||||
should be made on how <tt>CFGBlock</tt>s are numbered other than their
|
||||
numbers are unique and that they are numbered from 0..N-1 (where N is
|
||||
the number of basic blocks in the CFG).</p>
|
||||
|
||||
<h4>Entry and Exit Blocks</h4>
|
||||
|
||||
Each instance of <tt>CFG</tt> contains two special blocks:
|
||||
an <i>entry</i> block (accessible via <tt>CFG::getEntry()</tt>), which
|
||||
has no incoming edges, and an <i>exit</i> block (accessible
|
||||
via <tt>CFG::getExit()</tt>), which has no outgoing edges. Neither
|
||||
block contains any statements, and they serve the role of providing a
|
||||
clear entrance and exit for a body of code such as a function body.
|
||||
The presence of these empty blocks greatly simplifies the
|
||||
implementation of many analyses built on top of CFGs.
|
||||
|
||||
<h4 id ="ConditionalControlFlow">Conditional Control-Flow</h4>
|
||||
|
||||
<p>Conditional control-flow (such as those induced by if-statements
|
||||
and loops) is represented as edges between <tt>CFGBlock</tt>s.
|
||||
Because different C language constructs can induce control-flow,
|
||||
each <tt>CFGBlock</tt> also records an extra <tt>Stmt*</tt> that
|
||||
represents the <i>terminator</i> of the block. A terminator is simply
|
||||
the statement that caused the control-flow, and is used to identify
|
||||
the nature of the conditional control-flow between blocks. For
|
||||
example, in the case of an if-statement, the terminator refers to
|
||||
the <tt>IfStmt</tt> object in the AST that represented the given
|
||||
branch.</p>
|
||||
|
||||
<p>To illustrate, consider the following code example:</p>
|
||||
|
||||
<code>
|
||||
int foo(int x) {<br>
|
||||
x = x + 1;<br>
|
||||
<br>
|
||||
if (x > 2) x++;<br>
|
||||
else {<br>
|
||||
x += 2;<br>
|
||||
x *= 2;<br>
|
||||
}<br>
|
||||
<br>
|
||||
return x;<br>
|
||||
}
|
||||
</code>
|
||||
|
||||
<p>After invoking the parser+semantic analyzer on this code fragment,
|
||||
the AST of the body of <tt>foo</tt> is referenced by a
|
||||
single <tt>Stmt*</tt>. We can then construct an instance
|
||||
of <tt>CFG</tt> representing the control-flow graph of this function
|
||||
body by single call to a static class method:</p>
|
||||
|
||||
<code>
|
||||
Stmt* FooBody = ...<br>
|
||||
CFG* FooCFG = <b>CFG::buildCFG</b>(FooBody);
|
||||
</code>
|
||||
|
||||
<p>It is the responsibility of the caller of <tt>CFG::buildCFG</tt>
|
||||
to <tt>delete</tt> the returned <tt>CFG*</tt> when the CFG is no
|
||||
longer needed.</p>
|
||||
|
||||
<p>Along with providing an interface to iterate over
|
||||
its <tt>CFGBlock</tt>s, the <tt>CFG</tt> class also provides methods
|
||||
that are useful for debugging and visualizing CFGs. For example, the
|
||||
method
|
||||
<tt>CFG::dump()</tt> dumps a pretty-printed version of the CFG to
|
||||
standard error. This is especially useful when one is using a
|
||||
debugger such as gdb. For example, here is the output
|
||||
of <tt>FooCFG->dump()</tt>:</p>
|
||||
|
||||
<code>
|
||||
[ B5 (ENTRY) ]<br>
|
||||
Predecessors (0):<br>
|
||||
Successors (1): B4<br>
|
||||
<br>
|
||||
[ B4 ]<br>
|
||||
1: x = x + 1<br>
|
||||
2: (x > 2)<br>
|
||||
<b>T: if [B4.2]</b><br>
|
||||
Predecessors (1): B5<br>
|
||||
Successors (2): B3 B2<br>
|
||||
<br>
|
||||
[ B3 ]<br>
|
||||
1: x++<br>
|
||||
Predecessors (1): B4<br>
|
||||
Successors (1): B1<br>
|
||||
<br>
|
||||
[ B2 ]<br>
|
||||
1: x += 2<br>
|
||||
2: x *= 2<br>
|
||||
Predecessors (1): B4<br>
|
||||
Successors (1): B1<br>
|
||||
<br>
|
||||
[ B1 ]<br>
|
||||
1: return x;<br>
|
||||
Predecessors (2): B2 B3<br>
|
||||
Successors (1): B0<br>
|
||||
<br>
|
||||
[ B0 (EXIT) ]<br>
|
||||
Predecessors (1): B1<br>
|
||||
Successors (0):
|
||||
</code>
|
||||
|
||||
<p>For each block, the pretty-printed output displays for each block
|
||||
the number of <i>predecessor</i> blocks (blocks that have outgoing
|
||||
control-flow to the given block) and <i>successor</i> blocks (blocks
|
||||
that have control-flow that have incoming control-flow from the given
|
||||
block). We can also clearly see the special entry and exit blocks at
|
||||
the beginning and end of the pretty-printed output. For the entry
|
||||
block (block B5), the number of predecessor blocks is 0, while for the
|
||||
exit block (block B0) the number of successor blocks is 0.</p>
|
||||
|
||||
<p>The most interesting block here is B4, whose outgoing control-flow
|
||||
represents the branching caused by the sole if-statement
|
||||
in <tt>foo</tt>. Of particular interest is the second statement in
|
||||
the block, <b><tt>(x > 2)</tt></b>, and the terminator, printed
|
||||
as <b><tt>if [B4.2]</tt></b>. The second statement represents the
|
||||
evaluation of the condition of the if-statement, which occurs before
|
||||
the actual branching of control-flow. Within the <tt>CFGBlock</tt>
|
||||
for B4, the <tt>Stmt*</tt> for the second statement refers to the
|
||||
actual expression in the AST for <b><tt>(x > 2)</tt></b>. Thus
|
||||
pointers to subclasses of <tt>Expr</tt> can appear in the list of
|
||||
statements in a block, and not just subclasses of <tt>Stmt</tt> that
|
||||
refer to proper C statements.</p>
|
||||
|
||||
<p>The terminator of block B4 is a pointer to the <tt>IfStmt</tt>
|
||||
object in the AST. The pretty-printer outputs <b><tt>if
|
||||
[B4.2]</tt></b> because the condition expression of the if-statement
|
||||
has an actual place in the basic block, and thus the terminator is
|
||||
essentially
|
||||
<i>referring</i> to the expression that is the second statement of
|
||||
block B4 (i.e., B4.2). In this manner, conditions for control-flow
|
||||
(which also includes conditions for loops and switch statements) are
|
||||
hoisted into the actual basic block.</p>
|
||||
|
||||
<!--
|
||||
<h4>Implicit Control-Flow</h4>
|
||||
-->
|
||||
|
||||
<!--
|
||||
<p>A key design principle of the <tt>CFG</tt> class was to not require
|
||||
any transformations to the AST in order to represent control-flow.
|
||||
Thus the <tt>CFG</tt> does not perform any "lowering" of the
|
||||
statements in an AST: loops are not transformed into guarded gotos,
|
||||
short-circuit operations are not converted to a set of if-statements,
|
||||
and so on.</p>
|
||||
-->
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -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,246 +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
|
||||
};
|
||||
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;
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
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; }
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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 setComplexInt(const APSInt &R, const APSInt &I) {
|
||||
assert(isComplexInt() && "Invalid accessor");
|
||||
((ComplexAPSInt*)(void*)Data)->Real = R;
|
||||
((ComplexAPSInt*)(void*)Data)->Imag = I;
|
||||
}
|
||||
void setComplexFloat(const APFloat &R, const APFloat &I) {
|
||||
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) {
|
||||
if (Kind != RHS.Kind) {
|
||||
MakeUninit();
|
||||
if (RHS.isInt())
|
||||
MakeInt();
|
||||
else if (RHS.isFloat())
|
||||
MakeFloat();
|
||||
else if (RHS.isComplexInt())
|
||||
MakeComplexInt();
|
||||
else if (RHS.isComplexFloat())
|
||||
MakeComplexFloat();
|
||||
else if (RHS.isLValue())
|
||||
MakeLValue();
|
||||
}
|
||||
if (isInt())
|
||||
setInt(RHS.getInt());
|
||||
else if (isFloat())
|
||||
setFloat(RHS.getFloat());
|
||||
else if (isComplexInt())
|
||||
setComplexInt(RHS.getComplexIntReal(), RHS.getComplexIntImag());
|
||||
else if (isComplexFloat())
|
||||
setComplexFloat(RHS.getComplexFloatReal(), RHS.getComplexFloatImag());
|
||||
else if (isLValue())
|
||||
setLValue(RHS.getLValueBase(), RHS.getLValueOffset());
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
void MakeUninit() {
|
||||
if (Kind == Int)
|
||||
((APSInt*)(void*)Data)->~APSInt();
|
||||
else if (Kind == Float)
|
||||
((APFloat*)(void*)Data)->~APFloat();
|
||||
else if (Kind == ComplexInt)
|
||||
((ComplexAPSInt*)(void*)Data)->~ComplexAPSInt();
|
||||
else if (Kind == ComplexFloat)
|
||||
((ComplexAPFloat*)(void*)Data)->~ComplexAPFloat();
|
||||
else if (Kind == LValue) {
|
||||
((LV*)(void*)Data)->~LV();
|
||||
}
|
||||
}
|
||||
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 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;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#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 ScopedDecl::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,480 +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/LangOptions.h"
|
||||
#include "clang/AST/Builtins.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 TargetInfo;
|
||||
class SelectorTable;
|
||||
class SourceManager;
|
||||
// Decls
|
||||
class Decl;
|
||||
class ObjCPropertyDecl;
|
||||
class RecordDecl;
|
||||
class TagDecl;
|
||||
class TranslationUnitDecl;
|
||||
class TypeDecl;
|
||||
class TypedefDecl;
|
||||
|
||||
/// 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<ConstantArrayType> ConstantArrayTypes;
|
||||
llvm::FoldingSet<IncompleteArrayType> IncompleteArrayTypes;
|
||||
std::vector<VariableArrayType*> VariableArrayTypes;
|
||||
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;
|
||||
|
||||
llvm::SmallVector<const RecordType *, 8> EncodingRecordTypes;
|
||||
|
||||
/// 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;
|
||||
|
||||
/// Allocator - The allocator object used to create AST objects.
|
||||
llvm::MallocAllocator Allocator;
|
||||
|
||||
public:
|
||||
TargetInfo &Target;
|
||||
IdentifierTable &Idents;
|
||||
SelectorTable &Selectors;
|
||||
|
||||
SourceManager& getSourceManager() { return SourceMgr; }
|
||||
llvm::MallocAllocator &getAllocator() { return Allocator; }
|
||||
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;
|
||||
|
||||
ASTContext(const LangOptions& LOpts, SourceManager &SM, TargetInfo &t,
|
||||
IdentifierTable &idents, SelectorTable &sels,
|
||||
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);
|
||||
|
||||
/// 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);
|
||||
|
||||
/// 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);
|
||||
|
||||
/// 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 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();
|
||||
|
||||
// Return the ObjC type encoding for a given type.
|
||||
void getObjCEncodingForType(QualType t, std::string &S,
|
||||
llvm::SmallVector<const RecordType*,8> &RT) 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; }
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Type Predicates.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
/// 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;
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// 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(QualType T);
|
||||
|
||||
/// 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;
|
||||
}
|
||||
|
||||
/// getTypeAlign - Return the alignment of the specified type, in bits. This
|
||||
/// method does not work on incomplete types.
|
||||
unsigned getTypeAlign(QualType T) {
|
||||
return getTypeInfo(T).second;
|
||||
}
|
||||
|
||||
/// 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);
|
||||
//===--------------------------------------------------------------------===//
|
||||
// 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);
|
||||
|
||||
/// 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));
|
||||
}
|
||||
|
||||
/// 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);
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// 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);
|
||||
|
||||
/// setRecordDefinition - Used by RecordDecl::defineBody to inform ASTContext
|
||||
/// about which RecordDecl serves as the definition of a particular
|
||||
/// struct/union/class. This will eventually be used by enums as well.
|
||||
void setTagDefinition(TagDecl* R);
|
||||
friend class RecordDecl;
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
@@ -1,409 +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,
|
||||
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,
|
||||
Packed,
|
||||
StdCall,
|
||||
TransparentUnion,
|
||||
Unused,
|
||||
Visibility,
|
||||
Weak,
|
||||
Blocks,
|
||||
Const,
|
||||
Pure
|
||||
};
|
||||
|
||||
private:
|
||||
Attr *Next;
|
||||
Kind AttrKind;
|
||||
|
||||
protected:
|
||||
Attr(Kind AK) : Next(0), AttrKind(AK) {}
|
||||
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; }
|
||||
|
||||
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 {
|
||||
public:
|
||||
PackedAttr() : Attr(Packed) {}
|
||||
|
||||
// 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) {}
|
||||
|
||||
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 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 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 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 ObjCGCAttr *A) { return true; }
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
@@ -1,168 +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
|
||||
// c -> char
|
||||
// s -> short
|
||||
// i -> int
|
||||
// f -> float
|
||||
// d -> double
|
||||
// z -> size_t
|
||||
// F -> constant CFString
|
||||
// a -> __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, "UsUs", "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, "va&a", "n")
|
||||
BUILTIN(__builtin_stdarg_start, "va&a", "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*cz", "n")
|
||||
BUILTIN(__builtin_return_address, "v*Ui", "n")
|
||||
BUILTIN(__builtin_frame_address, "v*Ui", "n")
|
||||
// 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")
|
||||
|
||||
#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 strchr(GetRecord(ID).Type, 'a') != 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; }
|
||||
|
||||
Expr* getTerminatorCondition();
|
||||
|
||||
const Expr* 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
|
||||
@@ -1,986 +0,0 @@
|
||||
//===--- Decl.h - 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 subclasses.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_DECL_H
|
||||
#define LLVM_CLANG_AST_DECL_H
|
||||
|
||||
#include "clang/AST/DeclBase.h"
|
||||
#include "clang/Parse/AccessSpecifier.h"
|
||||
|
||||
namespace clang {
|
||||
class Expr;
|
||||
class Stmt;
|
||||
class StringLiteral;
|
||||
class IdentifierInfo;
|
||||
|
||||
/// TranslationUnitDecl - The top declaration context.
|
||||
/// FIXME: The TranslationUnit class should probably be modified to serve as
|
||||
/// the top decl context. It would have ownership of the top decls so that the
|
||||
/// AST is self-contained and easily de/serializable.
|
||||
class TranslationUnitDecl : public Decl, public DeclContext {
|
||||
TranslationUnitDecl()
|
||||
: Decl(TranslationUnit, SourceLocation()),
|
||||
DeclContext(TranslationUnit) {}
|
||||
public:
|
||||
static TranslationUnitDecl *Create(ASTContext &C);
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return D->getKind() == TranslationUnit; }
|
||||
static bool classof(const TranslationUnitDecl *D) { return true; }
|
||||
|
||||
protected:
|
||||
/// EmitImpl - Serialize this TranslationUnitDecl. Called by Decl::Emit.
|
||||
virtual void EmitImpl(llvm::Serializer& S) const;
|
||||
|
||||
/// CreateImpl - Deserialize a TranslationUnitDecl. Called by Decl::Create.
|
||||
static TranslationUnitDecl* CreateImpl(llvm::Deserializer& D, ASTContext& C);
|
||||
|
||||
friend Decl* Decl::Create(llvm::Deserializer& D, ASTContext& C);
|
||||
};
|
||||
|
||||
/// NamedDecl - This represents a decl with an identifier for a name. Many
|
||||
/// decls have names, but not ObjCMethodDecl, @class, etc.
|
||||
class NamedDecl : public Decl {
|
||||
/// Identifier - The identifier for this declaration (e.g. the name for the
|
||||
/// variable, the tag for a struct).
|
||||
IdentifierInfo *Identifier;
|
||||
public:
|
||||
NamedDecl(Kind DK, SourceLocation L, IdentifierInfo *Id)
|
||||
: Decl(DK, L), Identifier(Id) {}
|
||||
|
||||
IdentifierInfo *getIdentifier() const { return Identifier; }
|
||||
const char *getName() const;
|
||||
|
||||
static bool classof(const Decl *D) {
|
||||
return D->getKind() >= NamedFirst && D->getKind() <= NamedLast;
|
||||
}
|
||||
static bool classof(const NamedDecl *D) { return true; }
|
||||
|
||||
protected:
|
||||
void EmitInRec(llvm::Serializer& S) const;
|
||||
void ReadInRec(llvm::Deserializer& D, ASTContext& C);
|
||||
};
|
||||
|
||||
/// ScopedDecl - Represent lexically scoped names, used for all ValueDecl's
|
||||
/// and TypeDecl's.
|
||||
class ScopedDecl : public NamedDecl {
|
||||
/// NextDeclarator - If this decl was part of a multi-declarator declaration,
|
||||
/// such as "int X, Y, *Z;" this indicates Decl for the next declarator.
|
||||
ScopedDecl *NextDeclarator;
|
||||
|
||||
/// When this decl is in scope while parsing, the Next field contains a
|
||||
/// pointer to the shadowed decl of the same name. When the scope is popped,
|
||||
/// Decls are relinked onto a containing decl object.
|
||||
///
|
||||
ScopedDecl *Next;
|
||||
|
||||
DeclContext *DeclCtx;
|
||||
|
||||
protected:
|
||||
ScopedDecl(Kind DK, DeclContext *DC, SourceLocation L,
|
||||
IdentifierInfo *Id, ScopedDecl *PrevDecl)
|
||||
: NamedDecl(DK, L, Id), NextDeclarator(PrevDecl), Next(0), DeclCtx(DC) {}
|
||||
|
||||
public:
|
||||
DeclContext *getDeclContext() const { return DeclCtx; }
|
||||
|
||||
ScopedDecl *getNext() const { return Next; }
|
||||
void setNext(ScopedDecl *N) { Next = N; }
|
||||
|
||||
/// 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.
|
||||
ScopedDecl *getNextDeclarator() { return NextDeclarator; }
|
||||
const ScopedDecl *getNextDeclarator() const { return NextDeclarator; }
|
||||
void setNextDeclarator(ScopedDecl *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 {
|
||||
if (getDeclContext())
|
||||
return !getDeclContext()->isFunctionOrMethod();
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) {
|
||||
return D->getKind() >= ScopedFirst && D->getKind() <= ScopedLast;
|
||||
}
|
||||
static bool classof(const ScopedDecl *D) { return true; }
|
||||
|
||||
protected:
|
||||
void EmitInRec(llvm::Serializer& S) const;
|
||||
void ReadInRec(llvm::Deserializer& D, ASTContext& C);
|
||||
|
||||
void EmitOutRec(llvm::Serializer& S) const;
|
||||
void ReadOutRec(llvm::Deserializer& D, ASTContext& C);
|
||||
|
||||
friend void Decl::Destroy(ASTContext& C);
|
||||
};
|
||||
|
||||
/// NamespaceDecl - Represent a C++ namespace.
|
||||
class NamespaceDecl : public ScopedDecl, public DeclContext {
|
||||
SourceLocation LBracLoc, RBracLoc;
|
||||
|
||||
// For extended namespace definitions:
|
||||
//
|
||||
// namespace A { int x; }
|
||||
// namespace A { int y; }
|
||||
//
|
||||
// there will be one NamespaceDecl for each declaration.
|
||||
// NextDeclarator points to the next extended declaration.
|
||||
// OrigNamespace points to the original namespace declaration.
|
||||
// OrigNamespace of the first namespace decl points to itself.
|
||||
|
||||
NamespaceDecl *OrigNamespace;
|
||||
|
||||
NamespaceDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id)
|
||||
: ScopedDecl(Namespace, DC, L, Id, 0), DeclContext(Namespace) {
|
||||
OrigNamespace = this;
|
||||
}
|
||||
public:
|
||||
static NamespaceDecl *Create(ASTContext &C, DeclContext *DC,
|
||||
SourceLocation L, IdentifierInfo *Id);
|
||||
|
||||
virtual void Destroy(ASTContext& C);
|
||||
|
||||
NamespaceDecl *getNextNamespace() {
|
||||
return cast_or_null<NamespaceDecl>(getNextDeclarator());
|
||||
}
|
||||
const NamespaceDecl *getNextNamespace() const {
|
||||
return cast_or_null<NamespaceDecl>(getNextDeclarator());
|
||||
}
|
||||
void setNextNamespace(NamespaceDecl *ND) { setNextDeclarator(ND); }
|
||||
|
||||
NamespaceDecl *getOriginalNamespace() const {
|
||||
return OrigNamespace;
|
||||
}
|
||||
void setOriginalNamespace(NamespaceDecl *ND) { OrigNamespace = ND; }
|
||||
|
||||
SourceRange getSourceRange() const {
|
||||
return SourceRange(LBracLoc, RBracLoc);
|
||||
}
|
||||
|
||||
SourceLocation getLBracLoc() const { return LBracLoc; }
|
||||
SourceLocation getRBracLoc() const { return RBracLoc; }
|
||||
void setLBracLoc(SourceLocation LBrace) { LBracLoc = LBrace; }
|
||||
void setRBracLoc(SourceLocation RBrace) { RBracLoc = RBrace; }
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return D->getKind() == Namespace; }
|
||||
static bool classof(const NamespaceDecl *D) { return true; }
|
||||
|
||||
protected:
|
||||
/// EmitImpl - Serialize this NamespaceDecl. Called by Decl::Emit.
|
||||
virtual void EmitImpl(llvm::Serializer& S) const;
|
||||
|
||||
/// CreateImpl - Deserialize a NamespaceDecl. Called by Decl::Create.
|
||||
static NamespaceDecl* CreateImpl(llvm::Deserializer& D, ASTContext& C);
|
||||
|
||||
friend Decl* Decl::Create(llvm::Deserializer& D, ASTContext& C);
|
||||
};
|
||||
|
||||
/// ValueDecl - Represent the declaration of a variable (in which case it is
|
||||
/// an lvalue) a function (in which case it is a function designator) or
|
||||
/// an enum constant.
|
||||
class ValueDecl : public ScopedDecl {
|
||||
QualType DeclType;
|
||||
|
||||
protected:
|
||||
ValueDecl(Kind DK, DeclContext *DC, SourceLocation L,
|
||||
IdentifierInfo *Id, QualType T, ScopedDecl *PrevDecl)
|
||||
: ScopedDecl(DK, DC, L, Id, PrevDecl), DeclType(T) {}
|
||||
public:
|
||||
QualType getType() const { return DeclType; }
|
||||
void setType(QualType newType) { DeclType = newType; }
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) {
|
||||
return D->getKind() >= ValueFirst && D->getKind() <= ValueLast;
|
||||
}
|
||||
static bool classof(const ValueDecl *D) { return true; }
|
||||
|
||||
protected:
|
||||
void EmitInRec(llvm::Serializer& S) const;
|
||||
void ReadInRec(llvm::Deserializer& D, ASTContext& C);
|
||||
};
|
||||
|
||||
/// VarDecl - An instance of this class is created to represent a variable
|
||||
/// declaration or definition.
|
||||
class VarDecl : public ValueDecl {
|
||||
public:
|
||||
enum StorageClass {
|
||||
None, Auto, Register, Extern, Static, PrivateExtern
|
||||
};
|
||||
private:
|
||||
Stmt *Init;
|
||||
// FIXME: This can be packed into the bitfields in Decl.
|
||||
unsigned SClass : 3;
|
||||
bool ThreadSpecified : 1;
|
||||
bool HasCXXDirectInit : 1;
|
||||
|
||||
// Move to DeclGroup when it is implemented.
|
||||
SourceLocation TypeSpecStartLoc;
|
||||
friend class StmtIteratorBase;
|
||||
protected:
|
||||
VarDecl(Kind DK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id,
|
||||
QualType T, StorageClass SC, ScopedDecl *PrevDecl,
|
||||
SourceLocation TSSL = SourceLocation())
|
||||
: ValueDecl(DK, DC, L, Id, T, PrevDecl), Init(0),
|
||||
ThreadSpecified(false), HasCXXDirectInit(false),
|
||||
TypeSpecStartLoc(TSSL) { SClass = SC; }
|
||||
public:
|
||||
static VarDecl *Create(ASTContext &C, DeclContext *DC,
|
||||
SourceLocation L, IdentifierInfo *Id,
|
||||
QualType T, StorageClass S, ScopedDecl *PrevDecl,
|
||||
SourceLocation TypeSpecStartLoc = SourceLocation());
|
||||
|
||||
StorageClass getStorageClass() const { return (StorageClass)SClass; }
|
||||
|
||||
SourceLocation getTypeSpecStartLoc() const { return TypeSpecStartLoc; }
|
||||
|
||||
const Expr *getInit() const { return (const Expr*) Init; }
|
||||
Expr *getInit() { return (Expr*) Init; }
|
||||
void setInit(Expr *I) { Init = (Stmt*) I; }
|
||||
|
||||
void setThreadSpecified(bool T) { ThreadSpecified = T; }
|
||||
bool isThreadSpecified() const {
|
||||
return ThreadSpecified;
|
||||
}
|
||||
|
||||
void setCXXDirectInitializer(bool T) { HasCXXDirectInit = T; }
|
||||
|
||||
/// hasCXXDirectInitializer - If true, the initializer was a direct
|
||||
/// initializer, e.g: "int x(1);". The Init expression will be the expression
|
||||
/// inside the parens or a "ClassType(a,b,c)" class constructor expression for
|
||||
/// class types. Clients can distinguish between "int x(1);" and "int x=1;"
|
||||
/// by checking hasCXXDirectInitializer.
|
||||
///
|
||||
bool hasCXXDirectInitializer() const {
|
||||
return HasCXXDirectInit;
|
||||
}
|
||||
|
||||
/// hasLocalStorage - Returns true if a variable with function scope
|
||||
/// is a non-static local variable.
|
||||
bool hasLocalStorage() const {
|
||||
if (getStorageClass() == None)
|
||||
return !isFileVarDecl();
|
||||
|
||||
// Return true for: Auto, Register.
|
||||
// Return false for: Extern, Static, PrivateExtern.
|
||||
|
||||
return getStorageClass() <= Register;
|
||||
}
|
||||
|
||||
/// hasGlobalStorage - Returns true for all variables that do not
|
||||
/// have local storage. This includs all global variables as well
|
||||
/// as static variables declared within a function.
|
||||
bool hasGlobalStorage() const { return !hasLocalStorage(); }
|
||||
|
||||
/// isBlockVarDecl - Returns true for local variable declarations. Note that
|
||||
/// this includes static variables inside of functions.
|
||||
///
|
||||
/// void foo() { int x; static int y; extern int z; }
|
||||
///
|
||||
bool isBlockVarDecl() const {
|
||||
if (getKind() != Decl::Var)
|
||||
return false;
|
||||
if (DeclContext *DC = getDeclContext())
|
||||
return DC->isFunctionOrMethod();
|
||||
return false;
|
||||
}
|
||||
|
||||
/// isFileVarDecl - Returns true for file scoped variable declaration.
|
||||
bool isFileVarDecl() const {
|
||||
if (getKind() != Decl::Var)
|
||||
return false;
|
||||
if (isa<TranslationUnitDecl>(getDeclContext()) ||
|
||||
isa<NamespaceDecl>(getDeclContext()) )
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) {
|
||||
return D->getKind() >= VarFirst && D->getKind() <= VarLast;
|
||||
}
|
||||
static bool classof(const VarDecl *D) { return true; }
|
||||
|
||||
protected:
|
||||
void EmitInRec(llvm::Serializer& S) const;
|
||||
void ReadInRec(llvm::Deserializer& D, ASTContext& C);
|
||||
|
||||
void EmitOutRec(llvm::Serializer& S) const;
|
||||
void ReadOutRec(llvm::Deserializer& D, ASTContext& C);
|
||||
|
||||
/// EmitImpl - Serialize this VarDecl. Called by Decl::Emit.
|
||||
virtual void EmitImpl(llvm::Serializer& S) const;
|
||||
|
||||
/// ReadImpl - Deserialize this VarDecl. Called by subclasses.
|
||||
virtual void ReadImpl(llvm::Deserializer& D, ASTContext& C);
|
||||
|
||||
/// CreateImpl - Deserialize a VarDecl. Called by Decl::Create.
|
||||
static VarDecl* CreateImpl(llvm::Deserializer& D, ASTContext& C);
|
||||
};
|
||||
|
||||
class ImplicitParamDecl : public VarDecl {
|
||||
protected:
|
||||
ImplicitParamDecl(Kind DK, DeclContext *DC, SourceLocation L,
|
||||
IdentifierInfo *Id, QualType T, ScopedDecl *PrevDecl)
|
||||
: VarDecl(DK, DC, L, Id, T, VarDecl::None, PrevDecl) {}
|
||||
public:
|
||||
static ImplicitParamDecl *Create(ASTContext &C, DeclContext *DC,
|
||||
SourceLocation L, IdentifierInfo *Id,
|
||||
QualType T, ScopedDecl *PrevDecl);
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const ImplicitParamDecl *D) { return true; }
|
||||
static bool classof(const Decl *D) { return D->getKind() == ImplicitParam; }
|
||||
};
|
||||
|
||||
/// ParmVarDecl - Represent a parameter to a function.
|
||||
class ParmVarDecl : public VarDecl {
|
||||
// NOTE: VC++ treats enums as signed, avoid using the ObjCDeclQualifier enum
|
||||
/// FIXME: Also can be paced into the bitfields in Decl.
|
||||
/// in, inout, etc.
|
||||
unsigned objcDeclQualifier : 6;
|
||||
|
||||
/// Default argument, if any. [C++ Only]
|
||||
Expr *DefaultArg;
|
||||
|
||||
ParmVarDecl(DeclContext *DC, SourceLocation L,
|
||||
IdentifierInfo *Id, QualType T, StorageClass S,
|
||||
Expr *DefArg, ScopedDecl *PrevDecl)
|
||||
: VarDecl(ParmVar, DC, L, Id, T, S, PrevDecl),
|
||||
objcDeclQualifier(OBJC_TQ_None), DefaultArg(DefArg) {}
|
||||
|
||||
public:
|
||||
static ParmVarDecl *Create(ASTContext &C, DeclContext *DC,
|
||||
SourceLocation L,IdentifierInfo *Id,
|
||||
QualType T, StorageClass S, Expr *DefArg,
|
||||
ScopedDecl *PrevDecl);
|
||||
|
||||
ObjCDeclQualifier getObjCDeclQualifier() const {
|
||||
return ObjCDeclQualifier(objcDeclQualifier);
|
||||
}
|
||||
void setObjCDeclQualifier(ObjCDeclQualifier QTVal)
|
||||
{ objcDeclQualifier = QTVal; }
|
||||
|
||||
const Expr *getDefaultArg() const { return DefaultArg; }
|
||||
Expr *getDefaultArg() { return DefaultArg; }
|
||||
void setDefaultArg(Expr *defarg) { DefaultArg = defarg; }
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return D->getKind() == ParmVar; }
|
||||
static bool classof(const ParmVarDecl *D) { return true; }
|
||||
|
||||
protected:
|
||||
/// EmitImpl - Serialize this ParmVarDecl. Called by Decl::Emit.
|
||||
virtual void EmitImpl(llvm::Serializer& S) const;
|
||||
|
||||
/// CreateImpl - Deserialize a ParmVarDecl. Called by Decl::Create.
|
||||
static ParmVarDecl* CreateImpl(llvm::Deserializer& D, ASTContext& C);
|
||||
|
||||
friend Decl* Decl::Create(llvm::Deserializer& D, ASTContext& C);
|
||||
};
|
||||
|
||||
/// FunctionDecl - An instance of this class is created to represent a
|
||||
/// function declaration or definition.
|
||||
///
|
||||
/// Since a given function can be declared several times in a program,
|
||||
/// there may be several FunctionDecls that correspond to that
|
||||
/// function. Only one of those FunctionDecls will be found when
|
||||
/// traversing the list of declarations in the context of the
|
||||
/// FunctionDecl (e.g., the translation unit); this FunctionDecl
|
||||
/// contains all of the information known about the function. Other,
|
||||
/// previous declarations of the function are available via the
|
||||
/// getPreviousDeclaration() chain.
|
||||
class FunctionDecl : public ValueDecl, public DeclContext {
|
||||
public:
|
||||
enum StorageClass {
|
||||
None, Extern, Static, PrivateExtern
|
||||
};
|
||||
private:
|
||||
/// ParamInfo - new[]'d array of pointers to VarDecls for the formal
|
||||
/// parameters of this function. This is null if a prototype or if there are
|
||||
/// no formals. TODO: we could allocate this space immediately after the
|
||||
/// FunctionDecl object to save an allocation like FunctionType does.
|
||||
ParmVarDecl **ParamInfo;
|
||||
|
||||
Stmt *Body; // Null if a prototype.
|
||||
|
||||
/// PreviousDeclaration - A link to the previous declaration of this
|
||||
/// same function, NULL if this is the first declaration. For
|
||||
/// example, in the following code, the PreviousDeclaration can be
|
||||
/// traversed several times to see all three declarations of the
|
||||
/// function "f", the last of which is also a definition.
|
||||
///
|
||||
/// int f(int x, int y = 1);
|
||||
/// int f(int x = 0, int y);
|
||||
/// int f(int x, int y) { return x + y; }
|
||||
FunctionDecl *PreviousDeclaration;
|
||||
|
||||
// NOTE: VC++ treats enums as signed, avoid using the StorageClass enum
|
||||
unsigned SClass : 2;
|
||||
bool IsInline : 1;
|
||||
bool IsImplicit : 1;
|
||||
|
||||
// Move to DeclGroup when it is implemented.
|
||||
SourceLocation TypeSpecStartLoc;
|
||||
protected:
|
||||
FunctionDecl(Kind DK, DeclContext *DC, SourceLocation L,
|
||||
IdentifierInfo *Id, QualType T,
|
||||
StorageClass S, bool isInline, ScopedDecl *PrevDecl,
|
||||
SourceLocation TSSL = SourceLocation())
|
||||
: ValueDecl(DK, DC, L, Id, T, PrevDecl),
|
||||
DeclContext(DK),
|
||||
ParamInfo(0), Body(0), PreviousDeclaration(0),
|
||||
SClass(S), IsInline(isInline), IsImplicit(0), TypeSpecStartLoc(TSSL) {}
|
||||
|
||||
virtual ~FunctionDecl();
|
||||
virtual void Destroy(ASTContext& C);
|
||||
|
||||
public:
|
||||
static FunctionDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L,
|
||||
IdentifierInfo *Id, QualType T,
|
||||
StorageClass S = None, bool isInline = false,
|
||||
ScopedDecl *PrevDecl = 0,
|
||||
SourceLocation TSStartLoc = SourceLocation());
|
||||
|
||||
SourceLocation getTypeSpecStartLoc() const { return TypeSpecStartLoc; }
|
||||
|
||||
/// getBody - Retrieve the body (definition) of the function. The
|
||||
/// function body might be in any of the (re-)declarations of this
|
||||
/// function. The variant that accepts a FunctionDecl pointer will
|
||||
/// set that function declaration to the actual declaration
|
||||
/// containing the body (if there is one).
|
||||
Stmt *getBody(const FunctionDecl *&Definition) const;
|
||||
|
||||
virtual Stmt *getBody() const {
|
||||
const FunctionDecl* Definition;
|
||||
return getBody(Definition);
|
||||
}
|
||||
|
||||
/// isThisDeclarationADefinition - Returns whether this specific
|
||||
/// declaration of the function is also a definition. This does not
|
||||
/// determine whether the function has been defined (e.g., in a
|
||||
/// previous definition); for that information, use getBody.
|
||||
bool isThisDeclarationADefinition() const { return Body != 0; }
|
||||
|
||||
void setBody(Stmt *B) { Body = B; }
|
||||
|
||||
bool isImplicit() { return IsImplicit; }
|
||||
void setImplicit() { IsImplicit = true; }
|
||||
|
||||
/// getPreviousDeclaration - Return the previous declaration of this
|
||||
/// function.
|
||||
const FunctionDecl *getPreviousDeclaration() const {
|
||||
return PreviousDeclaration;
|
||||
}
|
||||
|
||||
void setPreviousDeclaration(FunctionDecl * PrevDecl) {
|
||||
PreviousDeclaration = PrevDecl;
|
||||
}
|
||||
|
||||
// Iterator access to formal parameters.
|
||||
unsigned param_size() const { return getNumParams(); }
|
||||
typedef ParmVarDecl **param_iterator;
|
||||
typedef ParmVarDecl * const *param_const_iterator;
|
||||
|
||||
param_iterator param_begin() { return ParamInfo; }
|
||||
param_iterator param_end() {
|
||||
|
||||
// Special-case for handling typedefs:
|
||||
//
|
||||
// typedef void func_t(int x);
|
||||
// func_t a;
|
||||
//
|
||||
// In the case of the FunctionDecl for "a", there are no ParmVarDecls.
|
||||
|
||||
return ParamInfo ? ParamInfo+param_size() : 0x0;
|
||||
}
|
||||
|
||||
param_const_iterator param_begin() const { return ParamInfo; }
|
||||
|
||||
param_const_iterator param_end() const {
|
||||
return ParamInfo ? ParamInfo+param_size() : 0x0;
|
||||
}
|
||||
|
||||
unsigned getNumParams() const;
|
||||
const ParmVarDecl *getParamDecl(unsigned i) const {
|
||||
assert(i < getNumParams() && "Illegal param #");
|
||||
return ParamInfo[i];
|
||||
}
|
||||
ParmVarDecl *getParamDecl(unsigned i) {
|
||||
assert(i < getNumParams() && "Illegal param #");
|
||||
return ParamInfo[i];
|
||||
}
|
||||
void setParams(ParmVarDecl **NewParamInfo, unsigned NumParams);
|
||||
|
||||
/// getMinRequiredArguments - Returns the minimum number of arguments
|
||||
/// needed to call this function. This may be fewer than the number of
|
||||
/// function parameters, if some of the parameters have default
|
||||
/// arguments (in C++).
|
||||
unsigned getMinRequiredArguments() const;
|
||||
|
||||
QualType getResultType() const {
|
||||
return getType()->getAsFunctionType()->getResultType();
|
||||
}
|
||||
StorageClass getStorageClass() const { return StorageClass(SClass); }
|
||||
bool isInline() const { return IsInline; }
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) {
|
||||
return D->getKind() >= FunctionFirst && D->getKind() <= FunctionLast;
|
||||
}
|
||||
static bool classof(const FunctionDecl *D) { return true; }
|
||||
|
||||
protected:
|
||||
/// EmitImpl - Serialize this FunctionDecl. Called by Decl::Emit.
|
||||
virtual void EmitImpl(llvm::Serializer& S) const;
|
||||
|
||||
/// CreateImpl - Deserialize a FunctionDecl. Called by Decl::Create.
|
||||
static FunctionDecl* CreateImpl(llvm::Deserializer& D, ASTContext& C);
|
||||
|
||||
friend Decl* Decl::Create(llvm::Deserializer& D, ASTContext& C);
|
||||
};
|
||||
|
||||
|
||||
/// FieldDecl - An instance of this class is created by Sema::ActOnField to
|
||||
/// represent a member of a struct/union/class.
|
||||
class FieldDecl : public NamedDecl {
|
||||
QualType DeclType;
|
||||
Expr *BitWidth;
|
||||
protected:
|
||||
FieldDecl(Kind DK, SourceLocation L, IdentifierInfo *Id, QualType T,
|
||||
Expr *BW = NULL)
|
||||
: NamedDecl(DK, L, Id), DeclType(T), BitWidth(BW) {}
|
||||
FieldDecl(SourceLocation L, IdentifierInfo *Id, QualType T, Expr *BW)
|
||||
: NamedDecl(Field, L, Id), DeclType(T), BitWidth(BW) {}
|
||||
public:
|
||||
static FieldDecl *Create(ASTContext &C, SourceLocation L, IdentifierInfo *Id,
|
||||
QualType T, Expr *BW = NULL);
|
||||
|
||||
QualType getType() const { return DeclType; }
|
||||
|
||||
bool isBitField() const { return BitWidth != NULL; }
|
||||
Expr *getBitWidth() const { return BitWidth; }
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) {
|
||||
return D->getKind() >= FieldFirst && D->getKind() <= FieldLast;
|
||||
}
|
||||
static bool classof(const FieldDecl *D) { return true; }
|
||||
|
||||
protected:
|
||||
/// EmitImpl - Serialize this FieldDecl. Called by Decl::Emit.
|
||||
virtual void EmitImpl(llvm::Serializer& S) const;
|
||||
|
||||
/// CreateImpl - Deserialize a FieldDecl. Called by Decl::Create.
|
||||
static FieldDecl* CreateImpl(llvm::Deserializer& D, ASTContext& C);
|
||||
|
||||
friend Decl* Decl::Create(llvm::Deserializer& D, ASTContext& C);
|
||||
};
|
||||
|
||||
/// EnumConstantDecl - An instance of this object exists for each enum constant
|
||||
/// that is defined. For example, in "enum X {a,b}", each of a/b are
|
||||
/// EnumConstantDecl's, X is an instance of EnumDecl, and the type of a/b is a
|
||||
/// TagType for the X EnumDecl.
|
||||
class EnumConstantDecl : public ValueDecl {
|
||||
Stmt *Init; // an integer constant expression
|
||||
llvm::APSInt Val; // The value.
|
||||
protected:
|
||||
EnumConstantDecl(DeclContext *DC, SourceLocation L,
|
||||
IdentifierInfo *Id, QualType T, Expr *E,
|
||||
const llvm::APSInt &V, ScopedDecl *PrevDecl)
|
||||
: ValueDecl(EnumConstant, DC, L, Id, T, PrevDecl), Init((Stmt*)E), Val(V) {}
|
||||
|
||||
virtual ~EnumConstantDecl() {}
|
||||
public:
|
||||
|
||||
static EnumConstantDecl *Create(ASTContext &C, EnumDecl *DC,
|
||||
SourceLocation L, IdentifierInfo *Id,
|
||||
QualType T, Expr *E,
|
||||
const llvm::APSInt &V, ScopedDecl *PrevDecl);
|
||||
|
||||
virtual void Destroy(ASTContext& C);
|
||||
|
||||
const Expr *getInitExpr() const { return (const Expr*) Init; }
|
||||
Expr *getInitExpr() { return (Expr*) Init; }
|
||||
const llvm::APSInt &getInitVal() const { return Val; }
|
||||
|
||||
void setInitExpr(Expr *E) { Init = (Stmt*) E; }
|
||||
void setInitVal(const llvm::APSInt &V) { Val = V; }
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return D->getKind() == EnumConstant; }
|
||||
static bool classof(const EnumConstantDecl *D) { return true; }
|
||||
|
||||
friend class StmtIteratorBase;
|
||||
|
||||
protected:
|
||||
/// EmitImpl - Serialize this EnumConstantDecl. Called by Decl::Emit.
|
||||
virtual void EmitImpl(llvm::Serializer& S) const;
|
||||
|
||||
/// CreateImpl - Deserialize a EnumConstantDecl. Called by Decl::Create.
|
||||
static EnumConstantDecl* CreateImpl(llvm::Deserializer& D, ASTContext& C);
|
||||
|
||||
friend Decl* Decl::Create(llvm::Deserializer& D, ASTContext& C);
|
||||
};
|
||||
|
||||
|
||||
/// TypeDecl - Represents a declaration of a type.
|
||||
///
|
||||
class TypeDecl : public ScopedDecl {
|
||||
/// TypeForDecl - This indicates the Type object that represents this
|
||||
/// TypeDecl. It is a cache maintained by ASTContext::getTypedefType and
|
||||
/// ASTContext::getTagDeclType.
|
||||
Type *TypeForDecl;
|
||||
friend class ASTContext;
|
||||
protected:
|
||||
TypeDecl(Kind DK, DeclContext *DC, SourceLocation L,
|
||||
IdentifierInfo *Id, ScopedDecl *PrevDecl)
|
||||
: ScopedDecl(DK, DC, L, Id, PrevDecl), TypeForDecl(0) {}
|
||||
public:
|
||||
void setAccess(AccessSpecifier AS) { Access = AS; }
|
||||
AccessSpecifier getAccess() const { return AccessSpecifier(Access); }
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) {
|
||||
return D->getKind() >= TypeFirst && D->getKind() <= TypeLast;
|
||||
}
|
||||
static bool classof(const TypeDecl *D) { return true; }
|
||||
};
|
||||
|
||||
|
||||
class TypedefDecl : public TypeDecl {
|
||||
/// UnderlyingType - This is the type the typedef is set to.
|
||||
QualType UnderlyingType;
|
||||
TypedefDecl(DeclContext *DC, SourceLocation L,
|
||||
IdentifierInfo *Id, QualType T, ScopedDecl *PD)
|
||||
: TypeDecl(Typedef, DC, L, Id, PD), UnderlyingType(T) {}
|
||||
|
||||
virtual ~TypedefDecl() {}
|
||||
public:
|
||||
|
||||
static TypedefDecl *Create(ASTContext &C, DeclContext *DC,
|
||||
SourceLocation L,IdentifierInfo *Id,
|
||||
QualType T, ScopedDecl *PD);
|
||||
|
||||
QualType getUnderlyingType() const { return UnderlyingType; }
|
||||
void setUnderlyingType(QualType newType) { UnderlyingType = newType; }
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return D->getKind() == Typedef; }
|
||||
static bool classof(const TypedefDecl *D) { return true; }
|
||||
|
||||
protected:
|
||||
/// EmitImpl - Serialize this TypedefDecl. Called by Decl::Emit.
|
||||
virtual void EmitImpl(llvm::Serializer& S) const;
|
||||
|
||||
/// CreateImpl - Deserialize a TypedefDecl. Called by Decl::Create.
|
||||
static TypedefDecl* CreateImpl(llvm::Deserializer& D, ASTContext& C);
|
||||
|
||||
friend Decl* Decl::Create(llvm::Deserializer& D, ASTContext& C);
|
||||
|
||||
};
|
||||
|
||||
|
||||
/// TagDecl - Represents the declaration of a struct/union/class/enum.
|
||||
class TagDecl : public TypeDecl {
|
||||
public:
|
||||
enum TagKind {
|
||||
TK_struct,
|
||||
TK_union,
|
||||
TK_class,
|
||||
TK_enum
|
||||
};
|
||||
|
||||
private:
|
||||
/// IsDefinition - True if this is a definition ("struct foo {};"), false if
|
||||
/// it is a declaration ("struct foo;").
|
||||
bool IsDefinition : 1;
|
||||
protected:
|
||||
TagDecl(Kind DK, DeclContext *DC, SourceLocation L,
|
||||
IdentifierInfo *Id, ScopedDecl *PrevDecl)
|
||||
: TypeDecl(DK, DC, L, Id, PrevDecl) {
|
||||
IsDefinition = false;
|
||||
}
|
||||
public:
|
||||
|
||||
/// isDefinition - Return true if this decl has its body specified.
|
||||
bool isDefinition() const {
|
||||
return IsDefinition;
|
||||
}
|
||||
|
||||
/// getDefinition - Returns the TagDecl that actually defines this
|
||||
/// struct/union/class/enum. When determining whether or not a
|
||||
/// struct/union/class/enum is completely defined, one should use this method
|
||||
/// as opposed to 'isDefinition'. 'isDefinition' indicates whether or not a
|
||||
/// specific TagDecl is defining declaration, not whether or not the
|
||||
/// struct/union/class/enum type is defined. This method returns NULL if
|
||||
/// there is no TagDecl that defines the struct/union/class/enum.
|
||||
TagDecl* getDefinition(ASTContext& C) const;
|
||||
|
||||
const char *getKindName() const {
|
||||
switch (getTagKind()) {
|
||||
default: assert(0 && "Unknown TagKind!");
|
||||
case TK_struct: return "struct";
|
||||
case TK_union: return "union";
|
||||
case TK_class: return "class";
|
||||
case TK_enum: return "enum";
|
||||
}
|
||||
}
|
||||
|
||||
TagKind getTagKind() const {
|
||||
switch (getKind()) {
|
||||
default: assert(0 && "Unknown TagDecl!");
|
||||
case Struct: case CXXStruct: return TK_struct;
|
||||
case Union: case CXXUnion: return TK_union;
|
||||
case Class: case CXXClass: return TK_class;
|
||||
case Enum: return TK_enum;
|
||||
}
|
||||
}
|
||||
|
||||
bool isStruct() const { return getKind() == Struct || getKind() == CXXStruct;}
|
||||
bool isClass() const { return getKind() == Class || getKind() == CXXClass; }
|
||||
bool isUnion() const { return getKind() == Union || getKind() == CXXUnion; }
|
||||
bool isEnum() const { return getKind() == Enum; }
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) {
|
||||
return D->getKind() >= TagFirst && D->getKind() <= TagLast;
|
||||
}
|
||||
static bool classof(const TagDecl *D) { return true; }
|
||||
protected:
|
||||
void setDefinition(bool V) { IsDefinition = V; }
|
||||
};
|
||||
|
||||
/// EnumDecl - Represents an enum. As an extension, we allow forward-declared
|
||||
/// enums.
|
||||
class EnumDecl : public TagDecl, public DeclContext {
|
||||
// EnumDecl's DeclChain points to a linked list of EnumConstantDecl's which
|
||||
// are linked together through their getNextDeclarator pointers.
|
||||
|
||||
/// IntegerType - This represent the integer type that the enum corresponds
|
||||
/// to for code generation purposes. Note that the enumerator constants may
|
||||
/// have a different type than this does.
|
||||
QualType IntegerType;
|
||||
|
||||
EnumDecl(DeclContext *DC, SourceLocation L,
|
||||
IdentifierInfo *Id, ScopedDecl *PrevDecl)
|
||||
: TagDecl(Enum, DC, L, Id, PrevDecl), DeclContext(Enum) {
|
||||
IntegerType = QualType();
|
||||
}
|
||||
public:
|
||||
static EnumDecl *Create(ASTContext &C, DeclContext *DC,
|
||||
SourceLocation L, IdentifierInfo *Id,
|
||||
ScopedDecl *PrevDecl);
|
||||
|
||||
virtual void Destroy(ASTContext& C);
|
||||
|
||||
/// defineElements - When created, EnumDecl correspond to a forward declared
|
||||
/// enum. This method is used to mark the decl as being defined, with the
|
||||
/// specified list of enums.
|
||||
void defineElements(EnumConstantDecl *ListHead, QualType NewType) {
|
||||
assert(!isDefinition() && "Cannot redefine enums!");
|
||||
setDeclChain(ListHead);
|
||||
setDefinition(true);
|
||||
|
||||
IntegerType = NewType;
|
||||
}
|
||||
|
||||
/// getIntegerType - Return the integer type this enum decl corresponds to.
|
||||
/// This returns a null qualtype for an enum forward definition.
|
||||
QualType getIntegerType() const { return IntegerType; }
|
||||
|
||||
/// getEnumConstantList - Return the first EnumConstantDecl in the enum.
|
||||
///
|
||||
EnumConstantDecl *getEnumConstantList() {
|
||||
return cast_or_null<EnumConstantDecl>(getDeclChain());
|
||||
}
|
||||
const EnumConstantDecl *getEnumConstantList() const {
|
||||
return cast_or_null<const EnumConstantDecl>(getDeclChain());
|
||||
}
|
||||
|
||||
static bool classof(const Decl *D) { return D->getKind() == Enum; }
|
||||
static bool classof(const EnumDecl *D) { return true; }
|
||||
|
||||
protected:
|
||||
/// EmitImpl - Serialize this EnumDecl. Called by Decl::Emit.
|
||||
virtual void EmitImpl(llvm::Serializer& S) const;
|
||||
|
||||
/// CreateImpl - Deserialize a EnumDecl. Called by Decl::Create.
|
||||
static EnumDecl* CreateImpl(llvm::Deserializer& D, ASTContext& C);
|
||||
|
||||
friend Decl* Decl::Create(llvm::Deserializer& D, ASTContext& C);
|
||||
};
|
||||
|
||||
|
||||
/// RecordDecl - Represents a struct/union/class. For example:
|
||||
/// struct X; // Forward declaration, no "body".
|
||||
/// union Y { int A, B; }; // Has body with members A and B (FieldDecls).
|
||||
/// This decl will be marked invalid if *any* members are invalid.
|
||||
///
|
||||
class RecordDecl : public TagDecl {
|
||||
/// HasFlexibleArrayMember - This is true if this struct ends with a flexible
|
||||
/// array member (e.g. int X[]) or if this union contains a struct that does.
|
||||
/// If so, this cannot be contained in arrays or other structs as a member.
|
||||
bool HasFlexibleArrayMember : 1;
|
||||
|
||||
/// Members/NumMembers - This is a new[]'d array of pointers to Decls.
|
||||
FieldDecl **Members; // Null if not defined.
|
||||
int NumMembers; // -1 if not defined.
|
||||
|
||||
protected:
|
||||
RecordDecl(Kind DK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id);
|
||||
virtual ~RecordDecl();
|
||||
|
||||
public:
|
||||
static RecordDecl *Create(ASTContext &C, TagKind TK, DeclContext *DC,
|
||||
SourceLocation L, IdentifierInfo *Id,
|
||||
RecordDecl* PrevDecl = 0);
|
||||
|
||||
virtual void Destroy(ASTContext& C);
|
||||
|
||||
bool hasFlexibleArrayMember() const { return HasFlexibleArrayMember; }
|
||||
void setHasFlexibleArrayMember(bool V) { HasFlexibleArrayMember = V; }
|
||||
|
||||
/// getDefinition - Returns the RecordDecl that actually defines this
|
||||
/// struct/union/class. When determining whether or not a struct/union/class
|
||||
/// is completely defined, one should use this method as opposed to
|
||||
/// 'isDefinition'. 'isDefinition' indicates whether or not a specific
|
||||
/// RecordDecl is defining declaration, not whether or not the record
|
||||
/// type is defined. This method returns NULL if there is no RecordDecl
|
||||
/// that defines the struct/union/tag.
|
||||
RecordDecl* getDefinition(ASTContext& C) const {
|
||||
return cast_or_null<RecordDecl>(TagDecl::getDefinition(C));
|
||||
}
|
||||
|
||||
/// getNumMembers - Return the number of members, or -1 if this is a forward
|
||||
/// definition.
|
||||
int getNumMembers() const { return NumMembers; }
|
||||
const FieldDecl *getMember(unsigned i) const { return Members[i]; }
|
||||
FieldDecl *getMember(unsigned i) { return Members[i]; }
|
||||
|
||||
// Iterator access to field members.
|
||||
typedef FieldDecl **field_iterator;
|
||||
typedef FieldDecl * const *field_const_iterator;
|
||||
|
||||
field_iterator field_begin() {
|
||||
assert(isDefinition() && "Not a definition!");
|
||||
return Members;
|
||||
}
|
||||
field_iterator field_end() {
|
||||
assert(isDefinition() && "Not a definition!");
|
||||
return Members + getNumMembers();
|
||||
}
|
||||
|
||||
field_const_iterator field_begin() const {
|
||||
assert(isDefinition() && "Not a definition!");
|
||||
return Members;
|
||||
}
|
||||
field_const_iterator field_end() const {
|
||||
assert(isDefinition() && "Not a definition!");
|
||||
return Members + getNumMembers();
|
||||
}
|
||||
|
||||
/// defineBody - When created, RecordDecl's correspond to a forward declared
|
||||
/// record. This method is used to mark the decl as being defined, with the
|
||||
/// specified contents.
|
||||
void defineBody(ASTContext& C, FieldDecl **Members, unsigned numMembers);
|
||||
|
||||
/// getMember - If the member doesn't exist, or there are no members, this
|
||||
/// function will return 0;
|
||||
FieldDecl *getMember(IdentifierInfo *name);
|
||||
|
||||
static bool classof(const Decl *D) {
|
||||
return D->getKind() >= RecordFirst && D->getKind() <= RecordLast;
|
||||
}
|
||||
static bool classof(const RecordDecl *D) { return true; }
|
||||
|
||||
protected:
|
||||
/// EmitImpl - Serialize this RecordDecl. Called by Decl::Emit.
|
||||
virtual void EmitImpl(llvm::Serializer& S) const;
|
||||
|
||||
/// CreateImpl - Deserialize a RecordDecl. Called by Decl::Create.
|
||||
static RecordDecl* CreateImpl(Kind DK, llvm::Deserializer& D, ASTContext& C);
|
||||
|
||||
friend Decl* Decl::Create(llvm::Deserializer& D, ASTContext& C);
|
||||
};
|
||||
|
||||
class FileScopeAsmDecl : public Decl {
|
||||
StringLiteral *AsmString;
|
||||
FileScopeAsmDecl(SourceLocation L, StringLiteral *asmstring)
|
||||
: Decl(FileScopeAsm, L), AsmString(asmstring) {}
|
||||
public:
|
||||
static FileScopeAsmDecl *Create(ASTContext &C, SourceLocation L,
|
||||
StringLiteral *Str);
|
||||
|
||||
const StringLiteral *getAsmString() const { return AsmString; }
|
||||
StringLiteral *getAsmString() { return AsmString; }
|
||||
static bool classof(const Decl *D) {
|
||||
return D->getKind() == FileScopeAsm;
|
||||
}
|
||||
static bool classof(const FileScopeAsmDecl *D) { return true; }
|
||||
protected:
|
||||
/// EmitImpl - Serialize this FileScopeAsmDecl. Called by Decl::Emit.
|
||||
virtual void EmitImpl(llvm::Serializer& S) const;
|
||||
|
||||
/// CreateImpl - Deserialize a FileScopeAsmDecl. Called by Decl::Create.
|
||||
static FileScopeAsmDecl* CreateImpl(llvm::Deserializer& D, ASTContext& C);
|
||||
|
||||
friend Decl* Decl::Create(llvm::Deserializer& D, ASTContext& C);
|
||||
};
|
||||
|
||||
/// LinkageSpecDecl - This represents a linkage specification. For example:
|
||||
/// extern "C" void foo();
|
||||
///
|
||||
class LinkageSpecDecl : public Decl {
|
||||
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;
|
||||
/// D - This is the Decl of the linkage specification.
|
||||
Decl *D;
|
||||
|
||||
LinkageSpecDecl(SourceLocation L, LanguageIDs lang, Decl *d)
|
||||
: Decl(LinkageSpec, L), Language(lang), D(d) {}
|
||||
public:
|
||||
static LinkageSpecDecl *Create(ASTContext &C, SourceLocation L,
|
||||
LanguageIDs Lang, Decl *D);
|
||||
|
||||
LanguageIDs getLanguage() const { return Language; }
|
||||
const Decl *getDecl() const { return D; }
|
||||
Decl *getDecl() { return D; }
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
@@ -1,403 +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"
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
|
||||
namespace clang {
|
||||
class TranslationUnitDecl;
|
||||
class NamespaceDecl;
|
||||
class ScopedDecl;
|
||||
class FunctionDecl;
|
||||
class CXXRecordDecl;
|
||||
class EnumDecl;
|
||||
class ObjCMethodDecl;
|
||||
class ObjCInterfaceDecl;
|
||||
|
||||
/// Decl - This represents one declaration (or definition), e.g. a variable,
|
||||
/// typedef, function, struct, etc.
|
||||
///
|
||||
class Decl {
|
||||
public:
|
||||
enum Kind {
|
||||
// This lists the concrete classes of Decl in order of the inheritance
|
||||
// hierarchy. This allows us to do efficient classof tests based on the
|
||||
// enums below. The commented out names are abstract class names.
|
||||
// [DeclContext] indicates that the class also inherits from DeclContext.
|
||||
|
||||
// Decl
|
||||
TranslationUnit, // [DeclContext]
|
||||
// NamedDecl
|
||||
Field,
|
||||
CXXField,
|
||||
ObjCIvar,
|
||||
ObjCAtDefsField,
|
||||
ObjCCategory,
|
||||
ObjCCategoryImpl,
|
||||
ObjCImplementation,
|
||||
ObjCProtocol,
|
||||
ObjCProperty,
|
||||
// ScopedDecl
|
||||
Namespace, // [DeclContext]
|
||||
// TypeDecl
|
||||
Typedef,
|
||||
// TagDecl
|
||||
Enum, // [DeclContext]
|
||||
// RecordDecl
|
||||
Struct,
|
||||
Union,
|
||||
Class,
|
||||
// CXXRecordDecl [DeclContext]
|
||||
CXXStruct,
|
||||
CXXUnion,
|
||||
CXXClass,
|
||||
// ValueDecl
|
||||
EnumConstant,
|
||||
Function, // [DeclContext]
|
||||
CXXMethod,
|
||||
Var,
|
||||
ImplicitParam,
|
||||
CXXClassVar,
|
||||
ParmVar,
|
||||
ObjCInterface, // [DeclContext]
|
||||
ObjCCompatibleAlias,
|
||||
ObjCMethod, // [DeclContext]
|
||||
ObjCClass,
|
||||
ObjCForwardProtocol,
|
||||
ObjCPropertyImpl,
|
||||
LinkageSpec,
|
||||
FileScopeAsm,
|
||||
|
||||
// For each non-leaf class, we now define a mapping to the first/last member
|
||||
// of the class, to allow efficient classof.
|
||||
NamedFirst = Field , NamedLast = ParmVar,
|
||||
FieldFirst = Field , FieldLast = ObjCAtDefsField,
|
||||
ScopedFirst = Namespace , ScopedLast = ParmVar,
|
||||
TypeFirst = Typedef , TypeLast = CXXClass,
|
||||
TagFirst = Enum , TagLast = CXXClass,
|
||||
RecordFirst = Struct , RecordLast = CXXClass,
|
||||
CXXRecordFirst = CXXStruct , CXXRecordLast = CXXClass,
|
||||
ValueFirst = EnumConstant , ValueLast = ParmVar,
|
||||
FunctionFirst = Function , FunctionLast = CXXMethod,
|
||||
VarFirst = Var , VarLast = ParmVar
|
||||
};
|
||||
|
||||
/// 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;
|
||||
|
||||
/// 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;
|
||||
|
||||
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, SourceLocation L) : Loc(L), DeclKind(DK), InvalidDecl(0),
|
||||
HasAttrs(false) {
|
||||
if (Decl::CollectingStats()) addDeclKind(DK);
|
||||
}
|
||||
|
||||
virtual ~Decl();
|
||||
|
||||
public:
|
||||
SourceLocation getLocation() const { return Loc; }
|
||||
void setLocation(SourceLocation L) { Loc = L; }
|
||||
|
||||
Kind getKind() const { return DeclKind; }
|
||||
const char *getDeclKindName() const;
|
||||
|
||||
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; }
|
||||
|
||||
IdentifierNamespace getIdentifierNamespace() const {
|
||||
switch (DeclKind) {
|
||||
default: assert(0 && "Unknown decl kind!");
|
||||
case ImplicitParam:
|
||||
case Typedef:
|
||||
case Function:
|
||||
case Var:
|
||||
case ParmVar:
|
||||
case EnumConstant:
|
||||
case ObjCInterface:
|
||||
case ObjCCompatibleAlias:
|
||||
case CXXField:
|
||||
case CXXMethod:
|
||||
case CXXClassVar:
|
||||
return IDNS_Ordinary;
|
||||
case Struct:
|
||||
case Union:
|
||||
case Class:
|
||||
case CXXStruct:
|
||||
case CXXUnion:
|
||||
case CXXClass:
|
||||
case Enum:
|
||||
return IDNS_Tag;
|
||||
case Namespace:
|
||||
return IdentifierNamespace(IDNS_Tag | IDNS_Ordinary);
|
||||
}
|
||||
}
|
||||
|
||||
// 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();
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *) { return true; }
|
||||
|
||||
/// 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.");
|
||||
}
|
||||
|
||||
void EmitInRec(llvm::Serializer& S) const;
|
||||
void ReadInRec(llvm::Deserializer& D, ASTContext& C);
|
||||
};
|
||||
|
||||
/// DeclContext - This is used only as base class of specific decl types that
|
||||
/// can act as declaration contexts. These decls are:
|
||||
///
|
||||
/// TranslationUnitDecl
|
||||
/// NamespaceDecl
|
||||
/// FunctionDecl
|
||||
/// CXXRecordDecl
|
||||
/// EnumDecl
|
||||
/// ObjCMethodDecl
|
||||
/// ObjCInterfaceDecl
|
||||
///
|
||||
class DeclContext {
|
||||
/// DeclKind - This indicates which class this is.
|
||||
Decl::Kind DeclKind : 8;
|
||||
|
||||
/// DeclChain - Linked list of declarations that are defined inside this
|
||||
/// declaration context.
|
||||
ScopedDecl *DeclChain;
|
||||
|
||||
// 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::ObjCMethod:
|
||||
return static_cast<ObjCMethodDecl*>(const_cast<From*>(D));
|
||||
case Decl::ObjCInterface:
|
||||
return static_cast<ObjCInterfaceDecl*>(const_cast<From*>(D));
|
||||
default:
|
||||
if (DK >= Decl::FunctionFirst && DK <= Decl::FunctionLast)
|
||||
return static_cast<FunctionDecl*>(const_cast<From*>(D));
|
||||
if (DK >= Decl::CXXRecordFirst && DK <= Decl::CXXRecordLast)
|
||||
return static_cast<CXXRecordDecl*>(const_cast<From*>(D));
|
||||
|
||||
assert(false && "a decl that inherits DeclContext isn't handled");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
DeclContext(Decl::Kind K) : DeclKind(K), DeclChain(0) {}
|
||||
|
||||
public:
|
||||
/// getParent - Returns the containing DeclContext if this is a ScopedDecl,
|
||||
/// else returns NULL.
|
||||
DeclContext *getParent() const;
|
||||
|
||||
bool isFunctionOrMethod() const {
|
||||
switch (DeclKind) {
|
||||
case Decl::Function:
|
||||
case Decl::CXXMethod:
|
||||
case Decl::ObjCMethod:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ScopedDecl *getDeclChain() const { return DeclChain; }
|
||||
void setDeclChain(ScopedDecl *D) { DeclChain = D; }
|
||||
|
||||
/// ToDecl and FromDecl make Decl <-> DeclContext castings.
|
||||
/// They are intended to be used by the simplify_type and cast_convert_val
|
||||
/// templates.
|
||||
static Decl *ToDecl (const DeclContext *D);
|
||||
static DeclContext *FromDecl (const Decl *D);
|
||||
|
||||
static bool classof(const Decl *D) {
|
||||
switch (D->getKind()) {
|
||||
case Decl::TranslationUnit:
|
||||
case Decl::Namespace:
|
||||
case Decl::Enum:
|
||||
case Decl::ObjCMethod:
|
||||
case Decl::ObjCInterface:
|
||||
return true;
|
||||
default:
|
||||
if (D->getKind() >= Decl::FunctionFirst &&
|
||||
D->getKind() <= Decl::FunctionLast)
|
||||
return true;
|
||||
if (D->getKind() >= Decl::CXXRecordFirst &&
|
||||
D->getKind() <= Decl::CXXRecordLast)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
static bool classof(const DeclContext *D) { return true; }
|
||||
static bool classof(const TranslationUnitDecl *D) { return true; }
|
||||
static bool classof(const NamespaceDecl *D) { return true; }
|
||||
static bool classof(const FunctionDecl *D) { return true; }
|
||||
static bool classof(const CXXRecordDecl *D) { return true; }
|
||||
static bool classof(const EnumDecl *D) { return true; }
|
||||
static bool classof(const ObjCMethodDecl *D) { return true; }
|
||||
static bool classof(const ObjCInterfaceDecl *D) { return true; }
|
||||
|
||||
private:
|
||||
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; }
|
||||
};
|
||||
|
||||
} // end clang.
|
||||
|
||||
namespace llvm {
|
||||
/// Implement simplify_type for DeclContext, so that we can dyn_cast from
|
||||
/// DeclContext to a specific Decl class.
|
||||
template<> struct simplify_type<const ::clang::DeclContext*> {
|
||||
typedef ::clang::Decl* SimpleType;
|
||||
static SimpleType getSimplifiedValue(const ::clang::DeclContext *Val) {
|
||||
return ::clang::DeclContext::ToDecl(Val);
|
||||
}
|
||||
};
|
||||
template<> struct simplify_type< ::clang::DeclContext*>
|
||||
: public simplify_type<const ::clang::DeclContext*> {};
|
||||
|
||||
template<> struct simplify_type<const ::clang::DeclContext> {
|
||||
typedef ::clang::Decl SimpleType;
|
||||
static SimpleType &getSimplifiedValue(const ::clang::DeclContext &Val) {
|
||||
return *::clang::DeclContext::ToDecl(&Val);
|
||||
}
|
||||
};
|
||||
template<> struct simplify_type< ::clang::DeclContext>
|
||||
: public simplify_type<const ::clang::DeclContext> {};
|
||||
|
||||
/// Implement cast_convert_val for DeclContext, so that we can dyn_cast from
|
||||
/// a Decl class to DeclContext.
|
||||
template<class FromTy>
|
||||
struct cast_convert_val< ::clang::DeclContext,const FromTy,const FromTy> {
|
||||
static ::clang::DeclContext &doit(const FromTy &Val) {
|
||||
return *::clang::DeclContext::FromDecl(&Val);
|
||||
}
|
||||
};
|
||||
template<class FromTy>
|
||||
struct cast_convert_val< ::clang::DeclContext,FromTy,FromTy>
|
||||
: public cast_convert_val< ::clang::DeclContext,const FromTy,const FromTy>
|
||||
{};
|
||||
|
||||
template<class FromTy>
|
||||
struct cast_convert_val< ::clang::DeclContext,const FromTy*,const FromTy*> {
|
||||
static ::clang::DeclContext *doit(const FromTy *Val) {
|
||||
return ::clang::DeclContext::FromDecl(Val);
|
||||
}
|
||||
};
|
||||
template<class FromTy>
|
||||
struct cast_convert_val< ::clang::DeclContext,FromTy*,FromTy*>
|
||||
: public cast_convert_val< ::clang::DeclContext,const FromTy*,const FromTy*>
|
||||
{};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
||||
@@ -1,194 +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"
|
||||
|
||||
namespace clang {
|
||||
class CXXRecordDecl;
|
||||
|
||||
/// CXXFieldDecl - Represents an instance field of a C++ struct/union/class.
|
||||
class CXXFieldDecl : public FieldDecl {
|
||||
CXXRecordDecl *Parent;
|
||||
|
||||
CXXFieldDecl(CXXRecordDecl *RD, SourceLocation L, IdentifierInfo *Id,
|
||||
QualType T, Expr *BW = NULL)
|
||||
: FieldDecl(CXXField, L, Id, T, BW), Parent(RD) {}
|
||||
public:
|
||||
static CXXFieldDecl *Create(ASTContext &C, CXXRecordDecl *RD,SourceLocation L,
|
||||
IdentifierInfo *Id, QualType T, Expr *BW = NULL);
|
||||
|
||||
void setAccess(AccessSpecifier AS) { Access = AS; }
|
||||
AccessSpecifier getAccess() const { return AccessSpecifier(Access); }
|
||||
CXXRecordDecl *getParent() const { return Parent; }
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return D->getKind() == CXXField; }
|
||||
static bool classof(const CXXFieldDecl *D) { return true; }
|
||||
};
|
||||
|
||||
/// CXXRecordDecl - Represents a C++ struct/union/class.
|
||||
/// The only difference with RecordDecl is that CXXRecordDecl is a DeclContext.
|
||||
class CXXRecordDecl : public RecordDecl, public DeclContext {
|
||||
protected:
|
||||
CXXRecordDecl(Kind DK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id)
|
||||
: RecordDecl(DK, DC, L, Id), DeclContext(DK) {
|
||||
assert(classof(static_cast<Decl*>(this)) && "Invalid Kind!");
|
||||
}
|
||||
public:
|
||||
static CXXRecordDecl *Create(ASTContext &C, TagKind TK, DeclContext *DC,
|
||||
SourceLocation L, IdentifierInfo *Id,
|
||||
CXXRecordDecl* PrevDecl=0);
|
||||
|
||||
const CXXFieldDecl *getMember(unsigned i) const {
|
||||
return cast<const CXXFieldDecl>(RecordDecl::getMember(i));
|
||||
}
|
||||
CXXFieldDecl *getMember(unsigned i) {
|
||||
return cast<CXXFieldDecl>(RecordDecl::getMember(i));
|
||||
}
|
||||
|
||||
/// getMember - If the member doesn't exist, or there are no members, this
|
||||
/// function will return 0;
|
||||
CXXFieldDecl *getMember(IdentifierInfo *name) {
|
||||
return cast_or_null<CXXFieldDecl>(RecordDecl::getMember(name));
|
||||
}
|
||||
|
||||
static bool classof(const Decl *D) {
|
||||
return D->getKind() >= CXXRecordFirst && D->getKind() <= CXXRecordLast;
|
||||
}
|
||||
static bool classof(const CXXRecordDecl *D) { return true; }
|
||||
|
||||
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 {
|
||||
|
||||
CXXMethodDecl(CXXRecordDecl *RD, SourceLocation L,
|
||||
IdentifierInfo *Id, QualType T,
|
||||
bool isStatic, bool isInline, ScopedDecl *PrevDecl)
|
||||
: FunctionDecl(CXXMethod, RD, L, Id, T, (isStatic ? Static : None),
|
||||
isInline, PrevDecl) {}
|
||||
public:
|
||||
static CXXMethodDecl *Create(ASTContext &C, CXXRecordDecl *RD,
|
||||
SourceLocation L, IdentifierInfo *Id,
|
||||
QualType T, bool isStatic = false,
|
||||
bool isInline = false, ScopedDecl *PrevDecl = 0);
|
||||
|
||||
bool isStatic() const { return getStorageClass() == Static; }
|
||||
bool isInstance() const { return !isStatic(); }
|
||||
|
||||
void setAccess(AccessSpecifier AS) { Access = AS; }
|
||||
AccessSpecifier getAccess() const { return AccessSpecifier(Access); }
|
||||
|
||||
/// getThisType - Returns the type of 'this' pointer.
|
||||
/// Should only be called for instance methods.
|
||||
QualType getThisType(ASTContext &C) const;
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return D->getKind() == CXXMethod; }
|
||||
static bool classof(const CXXMethodDecl *D) { return true; }
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
/// CXXClassVarDecl - Represents a static data member of a struct/union/class.
|
||||
class CXXClassVarDecl : public VarDecl {
|
||||
|
||||
CXXClassVarDecl(CXXRecordDecl *RD, SourceLocation L,
|
||||
IdentifierInfo *Id, QualType T, ScopedDecl *PrevDecl)
|
||||
: VarDecl(CXXClassVar, RD, L, Id, T, None, PrevDecl) {}
|
||||
public:
|
||||
static CXXClassVarDecl *Create(ASTContext &C, CXXRecordDecl *RD,
|
||||
SourceLocation L,IdentifierInfo *Id,
|
||||
QualType T, ScopedDecl *PrevDecl);
|
||||
|
||||
void setAccess(AccessSpecifier AS) { Access = AS; }
|
||||
AccessSpecifier getAccess() const { return AccessSpecifier(Access); }
|
||||
|
||||
// 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.
|
||||
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 {
|
||||
if (ScopedDecl *SD = dyn_cast<ScopedDecl>(MD)) {
|
||||
return cast<CXXRecordDecl>(SD->getDeclContext());
|
||||
}
|
||||
return cast<CXXFieldDecl>(MD)->getParent();
|
||||
}
|
||||
|
||||
static bool isMember(Decl *D) {
|
||||
if (ScopedDecl *SD = dyn_cast<ScopedDecl>(D)) {
|
||||
return isa<CXXRecordDecl>(SD->getDeclContext());
|
||||
}
|
||||
return isa<CXXFieldDecl>(D);
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
@@ -1,120 +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));
|
||||
}
|
||||
|
||||
const Decl*& operator[](unsigned i) const {
|
||||
assert (i < NumDecls && "Out-of-bounds access.");
|
||||
return *((const Decl**) (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;
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
/// 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(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.
|
||||
static DeclGroupOwningRef ReadVal(llvm::Deserializer& D, ASTContext& C);
|
||||
};
|
||||
|
||||
} // end clang namespace
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,276 +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/AST/Expr.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// C++ Expressions.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
/// CXXCastExpr - [C++ 5.2.7, 5.2.9, 5.2.10, 5.2.11] C++ Cast Operators.
|
||||
///
|
||||
class CXXCastExpr : public Expr {
|
||||
public:
|
||||
enum Opcode {
|
||||
DynamicCast,
|
||||
StaticCast,
|
||||
ReinterpretCast,
|
||||
ConstCast
|
||||
};
|
||||
private:
|
||||
QualType Ty;
|
||||
Opcode Opc;
|
||||
Stmt *Op;
|
||||
SourceLocation Loc; // the location of the casting op
|
||||
public:
|
||||
CXXCastExpr(Opcode op, QualType ty, Expr *expr, SourceLocation l)
|
||||
: Expr(CXXCastExprClass, ty), Ty(ty), Opc(op), Op(expr), Loc(l) {}
|
||||
|
||||
QualType getDestType() const { return Ty; }
|
||||
Expr *getSubExpr() const { return cast<Expr>(Op); }
|
||||
|
||||
Opcode getOpcode() const { return Opc; }
|
||||
|
||||
/// getOpcodeStr - Turn an Opcode enum value into the string it represents,
|
||||
/// e.g. "reinterpret_cast".
|
||||
static const char *getOpcodeStr(Opcode Op) {
|
||||
// FIXME: move out of line.
|
||||
switch (Op) {
|
||||
default: assert(0 && "Not a C++ cast expression");
|
||||
case CXXCastExpr::ConstCast: return "const_cast";
|
||||
case CXXCastExpr::DynamicCast: return "dynamic_cast";
|
||||
case CXXCastExpr::ReinterpretCast: return "reinterpret_cast";
|
||||
case CXXCastExpr::StaticCast: return "static_cast";
|
||||
}
|
||||
}
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return SourceRange(Loc, getSubExpr()->getSourceRange().getEnd());
|
||||
}
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CXXCastExprClass;
|
||||
}
|
||||
static bool classof(const CXXCastExpr *) { return true; }
|
||||
|
||||
// Iterators
|
||||
virtual child_iterator child_begin();
|
||||
virtual child_iterator child_end();
|
||||
};
|
||||
|
||||
/// 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();
|
||||
};
|
||||
|
||||
/// 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->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 - [C++ 5.2.3p1] Explicit type conversion
|
||||
/// (functional notation).
|
||||
/// Example: "x = int(0.5);"
|
||||
///
|
||||
class CXXFunctionalCastExpr : public CastExpr {
|
||||
SourceLocation TyBeginLoc;
|
||||
SourceLocation RParenLoc;
|
||||
public:
|
||||
CXXFunctionalCastExpr(QualType ty, SourceLocation tyBeginLoc, Expr *castExpr,
|
||||
SourceLocation rParenLoc) :
|
||||
CastExpr(CXXFunctionalCastExprClass, ty, castExpr),
|
||||
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);
|
||||
};
|
||||
|
||||
/// CXXZeroInitValueExpr - [C++ 5.2.3p2]
|
||||
/// Expression "T()" which creates a value-initialized Rvalue of non-class
|
||||
/// type T.
|
||||
///
|
||||
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; }
|
||||
|
||||
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(), 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);
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
@@ -1,418 +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();
|
||||
};
|
||||
|
||||
/// 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. Note that dot-syntax can also be used to access
|
||||
/// "implicit" properties (i.e. methods following the property naming
|
||||
/// convention). Additionally, sema is not yet smart enough to know if
|
||||
/// a property reference is to a getter or a setter, so the expr must
|
||||
/// have access to both methods.
|
||||
///
|
||||
// FIXME: Consider splitting these into separate Expr classes.
|
||||
class ObjCPropertyRefExpr : public Expr {
|
||||
public:
|
||||
enum Kind {
|
||||
PropertyRef, // This expressions references a declared property.
|
||||
MethodRef // This expressions references methods.
|
||||
};
|
||||
|
||||
private:
|
||||
// A dot-syntax reference via methods must always have a getter. We
|
||||
// avoid storing the kind explicitly by relying on this invariant
|
||||
// and assuming this is a MethodRef iff Getter is non-null. Setter
|
||||
// can be null in situations which access a read-only property.
|
||||
union {
|
||||
ObjCPropertyDecl *AsProperty;
|
||||
struct {
|
||||
ObjCMethodDecl *Setter;
|
||||
ObjCMethodDecl *Getter;
|
||||
} AsMethod;
|
||||
} Referent;
|
||||
SourceLocation Loc;
|
||||
Stmt *Base;
|
||||
|
||||
public:
|
||||
ObjCPropertyRefExpr(ObjCPropertyDecl *PD, QualType t,
|
||||
SourceLocation l, Expr *base)
|
||||
: Expr(ObjCPropertyRefExprClass, t), Loc(l), Base(base) {
|
||||
Referent.AsMethod.Getter = Referent.AsMethod.Setter = NULL;
|
||||
Referent.AsProperty = PD;
|
||||
}
|
||||
ObjCPropertyRefExpr(ObjCMethodDecl *Getter, ObjCMethodDecl *Setter,
|
||||
QualType t,
|
||||
SourceLocation l, Expr *base)
|
||||
: Expr(ObjCPropertyRefExprClass, t), Loc(l), Base(base) {
|
||||
Referent.AsMethod.Getter = Getter;
|
||||
Referent.AsMethod.Setter = Setter;
|
||||
}
|
||||
|
||||
Kind getKind() const {
|
||||
return Referent.AsMethod.Getter ? MethodRef : PropertyRef;
|
||||
}
|
||||
|
||||
ObjCPropertyDecl *getProperty() const {
|
||||
assert(getKind() == PropertyRef &&
|
||||
"Cannot get property from an ObjCPropertyRefExpr using methods");
|
||||
return Referent.AsProperty;
|
||||
}
|
||||
ObjCMethodDecl *getGetterMethod() const {
|
||||
assert(getKind() == MethodRef &&
|
||||
"Cannot get method from an ObjCPropertyRefExpr using a property");
|
||||
return Referent.AsMethod.Getter;
|
||||
}
|
||||
ObjCMethodDecl *getSetterMethod() const {
|
||||
assert(getKind() == MethodRef &&
|
||||
"Cannot get method from an ObjCPropertyRefExpr using a property");
|
||||
return Referent.AsMethod.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() == 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);
|
||||
};
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
} // 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,36 +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);
|
||||
}
|
||||
|
||||
bool isSubExpr(Stmt *S) const;
|
||||
};
|
||||
|
||||
} // 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,84 +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.
|
||||
void LayoutField(const FieldDecl *FD, unsigned FieldNo,
|
||||
bool IsUnion, bool StructIsPacked,
|
||||
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,129 +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 ScopedDecl;
|
||||
class VariableArrayType;
|
||||
|
||||
class StmtIteratorBase {
|
||||
protected:
|
||||
enum { DeclMode = 0x1, SizeOfTypeVAMode = 0x2, Flags = 0x3 };
|
||||
|
||||
union { Stmt** stmt; ScopedDecl* decl; };
|
||||
uintptr_t RawVAPtr;
|
||||
|
||||
bool inDecl() const {
|
||||
return RawVAPtr & DeclMode ? true : false;
|
||||
}
|
||||
|
||||
bool inSizeOfTypeVA() const {
|
||||
return RawVAPtr & SizeOfTypeVAMode ? true : false;
|
||||
}
|
||||
|
||||
VariableArrayType* getVAPtr() const {
|
||||
return reinterpret_cast<VariableArrayType*>(RawVAPtr & ~Flags);
|
||||
}
|
||||
|
||||
void setVAPtr(VariableArrayType* P) {
|
||||
assert (inDecl() || inSizeOfTypeVA());
|
||||
RawVAPtr = reinterpret_cast<uintptr_t>(P) | (RawVAPtr & Flags);
|
||||
}
|
||||
|
||||
void NextDecl(bool ImmediateAdvance = true);
|
||||
void NextVA();
|
||||
|
||||
Stmt*& GetDeclExpr() const;
|
||||
|
||||
StmtIteratorBase(Stmt** s) : stmt(s), RawVAPtr(0) {}
|
||||
StmtIteratorBase(ScopedDecl* d);
|
||||
StmtIteratorBase(VariableArrayType* t);
|
||||
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(ScopedDecl* d) : StmtIteratorBase(d) {}
|
||||
StmtIteratorImpl(VariableArrayType* t) : StmtIteratorBase(t) {}
|
||||
|
||||
DERIVED& operator++() {
|
||||
if (inDecl()) {
|
||||
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) (inDecl() || inSizeOfTypeVA() ? GetDeclExpr() : *stmt);
|
||||
}
|
||||
|
||||
REFERENCE operator->() const { return operator*(); }
|
||||
};
|
||||
|
||||
struct StmtIterator : public StmtIteratorImpl<StmtIterator,Stmt*&> {
|
||||
explicit StmtIterator() : StmtIteratorImpl<StmtIterator,Stmt*&>() {}
|
||||
|
||||
StmtIterator(Stmt** S) : StmtIteratorImpl<StmtIterator,Stmt*&>(S) {}
|
||||
|
||||
StmtIterator(VariableArrayType* t):StmtIteratorImpl<StmtIterator,Stmt*&>(t) {}
|
||||
StmtIterator(ScopedDecl* 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,121 +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(n)
|
||||
#define LAST_STMT(n)
|
||||
#endif
|
||||
|
||||
#ifndef FIRST_EXPR
|
||||
#define FIRST_EXPR(n)
|
||||
#define LAST_EXPR(n)
|
||||
#endif
|
||||
|
||||
// Normal Statements.
|
||||
FIRST_STMT(1)
|
||||
STMT( 1, NullStmt , Stmt)
|
||||
STMT( 2, CompoundStmt , Stmt)
|
||||
STMT( 3, CaseStmt , SwitchCase)
|
||||
STMT( 4, DefaultStmt , SwitchCase)
|
||||
STMT( 5, LabelStmt , Stmt)
|
||||
STMT( 6, IfStmt , Stmt)
|
||||
STMT( 7, SwitchStmt , Stmt)
|
||||
STMT( 8, WhileStmt , Stmt)
|
||||
STMT( 9, DoStmt , Stmt)
|
||||
STMT(10, ForStmt , Stmt)
|
||||
STMT(11, GotoStmt , Stmt)
|
||||
STMT(12, IndirectGotoStmt, Stmt)
|
||||
STMT(13, ContinueStmt , Stmt)
|
||||
STMT(14, BreakStmt , Stmt)
|
||||
STMT(15, ReturnStmt , Stmt)
|
||||
STMT(16, DeclStmt , Stmt)
|
||||
STMT(17, SwitchCase , Stmt)
|
||||
|
||||
// GNU Stmt Extensions
|
||||
STMT(18, AsmStmt , Stmt)
|
||||
|
||||
// Obj-C statements
|
||||
STMT(19, ObjCAtTryStmt , Stmt)
|
||||
STMT(20, ObjCAtCatchStmt , Stmt)
|
||||
STMT(21, ObjCAtFinallyStmt , Stmt)
|
||||
STMT(22, ObjCAtThrowStmt , Stmt)
|
||||
STMT(23, ObjCAtSynchronizedStmt , Stmt)
|
||||
// Obj-C2 statements
|
||||
STMT(24, ObjCForCollectionStmt, Stmt)
|
||||
|
||||
LAST_STMT(23)
|
||||
|
||||
FIRST_EXPR(31)
|
||||
// Expressions.
|
||||
STMT(31, Expr , Stmt)
|
||||
STMT(32, PredefinedExpr , Expr)
|
||||
STMT(33, DeclRefExpr , Expr)
|
||||
STMT(34, IntegerLiteral , Expr)
|
||||
STMT(35, FloatingLiteral , Expr)
|
||||
STMT(36, ImaginaryLiteral , Expr)
|
||||
STMT(37, StringLiteral , Expr)
|
||||
STMT(38, CharacterLiteral , Expr)
|
||||
STMT(39, ParenExpr , Expr)
|
||||
STMT(40, UnaryOperator , Expr)
|
||||
STMT(41, SizeOfAlignOfTypeExpr , Expr)
|
||||
STMT(42, ArraySubscriptExpr , Expr)
|
||||
STMT(43, CallExpr , Expr)
|
||||
STMT(44, MemberExpr , Expr)
|
||||
STMT(45, CastExpr , Expr)
|
||||
STMT(46, BinaryOperator , Expr)
|
||||
STMT(47, CompoundAssignOperator, BinaryOperator)
|
||||
STMT(48, ConditionalOperator , Expr)
|
||||
STMT(49, ImplicitCastExpr , CastExpr)
|
||||
STMT(50, ExplicitCastExpr , CastExpr)
|
||||
STMT(51, CompoundLiteralExpr , Expr)
|
||||
STMT(52, ExtVectorElementExpr , Expr)
|
||||
STMT(53, InitListExpr , Expr)
|
||||
STMT(54, VAArgExpr , Expr)
|
||||
|
||||
// GNU Extensions.
|
||||
STMT(55, AddrLabelExpr , Expr)
|
||||
STMT(56, StmtExpr , Expr)
|
||||
STMT(57, TypesCompatibleExpr , Expr)
|
||||
STMT(58, ChooseExpr , Expr)
|
||||
|
||||
// C++ Expressions.
|
||||
STMT(60, CXXCastExpr , Expr)
|
||||
STMT(61, CXXBoolLiteralExpr , Expr)
|
||||
STMT(62, CXXThrowExpr , Expr)
|
||||
STMT(63, CXXDefaultArgExpr , Expr)
|
||||
STMT(64, CXXFunctionalCastExpr, CastExpr)
|
||||
STMT(65, CXXZeroInitValueExpr , Expr)
|
||||
STMT(66, CXXConditionDeclExpr , DeclRefExpr)
|
||||
|
||||
// Obj-C Expressions.
|
||||
STMT(70, ObjCStringLiteral , Expr)
|
||||
STMT(71, ObjCEncodeExpr , Expr)
|
||||
STMT(72, ObjCMessageExpr , Expr)
|
||||
STMT(73, ObjCSelectorExpr , Expr)
|
||||
STMT(74, ObjCProtocolExpr , Expr)
|
||||
STMT(75, ObjCIvarRefExpr , Expr)
|
||||
STMT(76, ObjCPropertyRefExpr , Expr)
|
||||
|
||||
// Clang Extensions.
|
||||
STMT(77, OverloadExpr , Expr)
|
||||
STMT(78, ShuffleVectorExpr , Expr)
|
||||
STMT(79, BlockExpr , Expr)
|
||||
STMT(80, BlockDeclRefExpr , Expr)
|
||||
|
||||
LAST_EXPR(80)
|
||||
|
||||
#undef STMT
|
||||
#undef FIRST_STMT
|
||||
#undef LAST_STMT
|
||||
#undef FIRST_EXPR
|
||||
#undef LAST_EXPR
|
||||
@@ -1,174 +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::SizeOf: DISPATCH(UnarySizeOf, UnaryOperator);
|
||||
case UnaryOperator::AlignOf: DISPATCH(UnaryAlignOf, 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(N, 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(N, 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(SizeOf) UNARYOP_FALLBACK(AlignOf)
|
||||
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,112 +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 "llvm/Bitcode/SerializationFwd.h"
|
||||
#include "llvm/System/Path.h"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace clang {
|
||||
|
||||
class FileManager;
|
||||
class SourceManager;
|
||||
class TargetInfo;
|
||||
class IdentifierTable;
|
||||
class SelectorTable;
|
||||
class ASTContext;
|
||||
class Decl;
|
||||
class FileEntry;
|
||||
|
||||
class TranslationUnit {
|
||||
ASTContext* Context;
|
||||
std::vector<Decl*> TopLevelDecls;
|
||||
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; }
|
||||
|
||||
/// AddTopLevelDecl - Add a top-level declaration to the translation unit.
|
||||
/// Ownership of the Decl is transfered to the TranslationUnit object.
|
||||
void AddTopLevelDecl(Decl* d) {
|
||||
TopLevelDecls.push_back(d);
|
||||
}
|
||||
|
||||
typedef std::vector<Decl*>::iterator iterator;
|
||||
iterator begin() { return TopLevelDecls.begin(); }
|
||||
iterator end() { return TopLevelDecls.end(); }
|
||||
|
||||
typedef std::vector<Decl*>::const_iterator const_iterator;
|
||||
const_iterator begin() const { return TopLevelDecls.begin(); }
|
||||
const_iterator end() const { return TopLevelDecls.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,465 +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", "")
|
||||
// FIXME: the prototype for __builtin_ia32_movntq changed across different
|
||||
// versions of GCC. Until we can replace GCC's xmmintrin.h, this is hacked to
|
||||
// be a vararg builtin instead of taking V1LLi like it should. This loses some
|
||||
// type checking but makes us compatible with old version of GCC's xmmintrin.h
|
||||
// file.
|
||||
BUILTIN(__builtin_ia32_movntq, "vV1LLi*.", "")
|
||||
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_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_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/ExprDeclBitVector.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 ExprDeclBitVector_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 ExprDeclBitVector_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(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/ExprDeclBitVector.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 ExprDeclBitVector_Types::AnalysisDataTy {
|
||||
AnalysisDataTy() : Observer(NULL), FullUninitTaint(true) {}
|
||||
virtual ~AnalysisDataTy() {};
|
||||
|
||||
ObserverTy* Observer;
|
||||
bool FullUninitTaint;
|
||||
};
|
||||
|
||||
typedef ExprDeclBitVector_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,311 +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 ResetValues(CFG& cfg, ValTy& V, const CFGBlock* B,
|
||||
dataflow::forward_analysis_tag){
|
||||
|
||||
if (B == &cfg.getEntry())
|
||||
TF.SetTopValue(V);
|
||||
else
|
||||
V.resetValues(D.getAnalysisData());
|
||||
}
|
||||
|
||||
void ResetValues(CFG& cfg, ValTy& V, const CFGBlock* B,
|
||||
dataflow::backward_analysis_tag){
|
||||
|
||||
if (B == &cfg.getExit())
|
||||
TF.SetTopValue(V);
|
||||
else
|
||||
V.resetValues(D.getAnalysisData());
|
||||
}
|
||||
|
||||
void ProcessMerge(CFG& cfg, const CFGBlock* B) {
|
||||
|
||||
ValTy& V = TF.getVal();
|
||||
ResetValues(cfg, V, B, AnalysisDirTag());
|
||||
|
||||
// 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,213 +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::vector<std::string> OtherDesc;
|
||||
|
||||
public:
|
||||
PathDiagnostic() : Size(0) {}
|
||||
|
||||
PathDiagnostic(const char* desc, const char* category)
|
||||
: Size(0), Desc(desc), Category(category) {}
|
||||
|
||||
PathDiagnostic(const std::string& desc, const std::string& category)
|
||||
: Size(0), Desc(desc), Category(category) {}
|
||||
|
||||
~PathDiagnostic();
|
||||
|
||||
const std::string& getDescription() const { return Desc; }
|
||||
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 &Diags,
|
||||
Diagnostic::Level DiagLevel,
|
||||
FullSourceLoc Pos,
|
||||
diag::kind ID,
|
||||
const std::string *Strs,
|
||||
unsigned NumStrs,
|
||||
const SourceRange *Ranges,
|
||||
unsigned NumRanges);
|
||||
|
||||
virtual void HandlePathDiagnostic(const PathDiagnostic* D) = 0;
|
||||
};
|
||||
|
||||
} //end clang namespace
|
||||
#endif
|
||||
@@ -1,86 +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/AST/ASTContext.h"
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
#include "llvm/ADT/APSInt.h"
|
||||
|
||||
namespace llvm {
|
||||
class BumpPtrAllocator;
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
|
||||
class RVal;
|
||||
|
||||
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* PersistentRVals;
|
||||
void* PersistentRValPairs;
|
||||
|
||||
public:
|
||||
BasicValueFactory(ASTContext& ctx, llvm::BumpPtrAllocator& Alloc)
|
||||
: Ctx(ctx), BPAlloc(Alloc), PersistentRVals(0), PersistentRValPairs(0) {}
|
||||
|
||||
~BasicValueFactory();
|
||||
|
||||
ASTContext& getContext() const { return Ctx; }
|
||||
|
||||
const llvm::APSInt& getValue(const llvm::APSInt& X);
|
||||
const llvm::APSInt& getValue(uint64_t X, unsigned BitWidth, bool isUnsigned);
|
||||
const llvm::APSInt& getValue(uint64_t X, QualType T);
|
||||
|
||||
inline const llvm::APSInt& getZeroWithPtrWidth() {
|
||||
return getValue(0, Ctx.getTypeSize(Ctx.VoidPtrTy), true);
|
||||
}
|
||||
|
||||
inline const llvm::APSInt& getTruthValue(bool b) {
|
||||
return getValue(b ? 1 : 0, Ctx.getTypeSize(Ctx.IntTy), false);
|
||||
}
|
||||
|
||||
const SymIntConstraint& getConstraint(SymbolID sym, BinaryOperator::Opcode Op,
|
||||
const llvm::APSInt& V);
|
||||
|
||||
const llvm::APSInt* EvaluateAPSInt(BinaryOperator::Opcode Op,
|
||||
const llvm::APSInt& V1,
|
||||
const llvm::APSInt& V2);
|
||||
|
||||
const std::pair<RVal, uintptr_t>&
|
||||
getPersistentRValWithData(const RVal& V, uintptr_t Data);
|
||||
|
||||
const std::pair<RVal, RVal>&
|
||||
getPersistentRValPair(const RVal& V1, const RVal& V2);
|
||||
|
||||
const RVal* getPersistentRVal(RVal X);
|
||||
};
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
#endif
|
||||
@@ -1,352 +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 <vector>
|
||||
#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;
|
||||
ExplodedNode<GRState> *EndNode;
|
||||
SourceRange R;
|
||||
public:
|
||||
BugReport(BugType& D, ExplodedNode<GRState> *n) : Desc(D), EndNode(n) {}
|
||||
virtual ~BugReport();
|
||||
|
||||
const BugType& getBugType() const { return Desc; }
|
||||
BugType& getBugType() { return Desc; }
|
||||
|
||||
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,
|
||||
ExplodedNode<GRState>* N);
|
||||
|
||||
virtual FullSourceLoc getLocation(SourceManager& Mgr);
|
||||
|
||||
virtual void getRanges(BugReporter& BR,const SourceRange*& beg,
|
||||
const SourceRange*& end);
|
||||
|
||||
virtual PathDiagnosticPiece* VisitNode(ExplodedNode<GRState>* N,
|
||||
ExplodedNode<GRState>* PrevN,
|
||||
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<SymbolID, 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(SymbolID Sym) {
|
||||
NotableSymbols.insert(Sym);
|
||||
}
|
||||
|
||||
bool isNotable(SymbolID 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() {}
|
||||
|
||||
virtual void HandleDiagnostic(Diagnostic &Diags,
|
||||
Diagnostic::Level DiagLevel,
|
||||
FullSourceLoc Pos,
|
||||
diag::kind ID,
|
||||
const std::string *Strs,
|
||||
unsigned NumStrs,
|
||||
const SourceRange *Ranges,
|
||||
unsigned NumRanges) {
|
||||
|
||||
// FIXME: Use a map from diag::kind to BugType, instead of having just
|
||||
// one BugType.
|
||||
|
||||
Reports.push_back(DiagBugReport(Diags.getDescription(ID), D, Pos));
|
||||
DiagBugReport& R = Reports.back();
|
||||
|
||||
for ( ; NumRanges ; --NumRanges, ++Ranges)
|
||||
R.addRange(*Ranges);
|
||||
|
||||
for ( ; NumStrs ; --NumStrs, ++Strs)
|
||||
R.addString(*Strs);
|
||||
}
|
||||
|
||||
// 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,56 +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 RVal;
|
||||
class SymbolID;
|
||||
|
||||
class ConstraintManager {
|
||||
public:
|
||||
virtual ~ConstraintManager();
|
||||
virtual const GRState* Assume(const GRState* St, RVal Cond, bool Assumption,
|
||||
bool& isFeasible) = 0;
|
||||
|
||||
virtual const GRState* AddNE(const GRState* St, SymbolID sym,
|
||||
const llvm::APSInt& V) = 0;
|
||||
virtual const llvm::APSInt* getSymVal(const GRState* St, SymbolID sym) = 0;
|
||||
|
||||
virtual bool isEqual(const GRState* St, SymbolID sym,
|
||||
const llvm::APSInt& V) const = 0;
|
||||
|
||||
virtual const GRState* RemoveDeadBindings(const GRState* St,
|
||||
StoreManager::LiveSymbolsTy& LSymbols,
|
||||
StoreManager::DeadSymbolsTy& DSymbols) = 0;
|
||||
|
||||
virtual void print(const GRState* St, std::ostream& Out,
|
||||
const char* nl, const char *sep) = 0;
|
||||
};
|
||||
|
||||
ConstraintManager* CreateBasicConstraintManager(GRStateManager& statemgr);
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
#endif
|
||||
@@ -1,150 +0,0 @@
|
||||
//== Environment.h - Map from Expr* 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/RValues.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<Expr*,RVal> 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(); }
|
||||
|
||||
RVal LookupSubExpr(Expr* E) const {
|
||||
const RVal* X = SubExprBindings.lookup(E);
|
||||
return X ? *X : UnknownVal();
|
||||
}
|
||||
|
||||
RVal LookupBlkExpr(Expr* E) const {
|
||||
const RVal* X = BlkExprBindings.lookup(E);
|
||||
return X ? *X : UnknownVal();
|
||||
}
|
||||
|
||||
RVal LookupExpr(Expr* E) const {
|
||||
const RVal* X = SubExprBindings.lookup(E);
|
||||
if (X) return *X;
|
||||
X = BlkExprBindings.lookup(E);
|
||||
return X ? *X : UnknownVal();
|
||||
}
|
||||
|
||||
RVal GetRVal(Expr* Ex, BasicValueFactory& BasicVals) const;
|
||||
RVal GetBlkExprRVal(Expr* 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 Expr*
|
||||
/// 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, Expr* E) {
|
||||
return Environment(Env.SubExprBindings, F.Remove(Env.BlkExprBindings, E));
|
||||
}
|
||||
|
||||
Environment RemoveSubExpr(const Environment& Env, Expr* E) {
|
||||
return Environment(F.Remove(Env.SubExprBindings, E), Env.BlkExprBindings);
|
||||
}
|
||||
|
||||
Environment AddBlkExpr(const Environment& Env, Expr* E, RVal V) {
|
||||
return Environment(Env.SubExprBindings, F.Add(Env.BlkExprBindings, E, V));
|
||||
}
|
||||
|
||||
Environment AddSubExpr(const Environment& Env, Expr* E, RVal 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 SetRVal(const Environment& Env, Expr* E, RVal V,
|
||||
bool isBlkExpr, bool Invalidate);
|
||||
|
||||
Environment RemoveDeadBindings(Environment Env, Stmt* Loc,
|
||||
const LiveVariables& Liveness,
|
||||
llvm::SmallVectorImpl<const MemRegion*>& DRoots,
|
||||
StoreManager::LiveSymbolsTy& LSymbols);
|
||||
};
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
#endif
|
||||
@@ -1,525 +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_succ_iterator;
|
||||
typedef ExplodedNode** pred_iterator;
|
||||
typedef const ExplodedNode** 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(ExplodedNodeImpl** NBeg,
|
||||
ExplodedNodeImpl** 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(NodeTy** NBeg, NodeTy** NEnd) const {
|
||||
|
||||
if (NBeg == NEnd)
|
||||
return NULL;
|
||||
|
||||
assert (NBeg < NEnd);
|
||||
|
||||
ExplodedNodeImpl** NBegImpl = (ExplodedNodeImpl**) NBeg;
|
||||
ExplodedNodeImpl** NEndImpl = (ExplodedNodeImpl**) 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,639 +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(Expr* 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(Expr* 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,
|
||||
ProgramPoint::Kind K = ProgramPoint::PostStmtKind) {
|
||||
|
||||
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(Expr* 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::MakeDFS()),
|
||||
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,645 +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;
|
||||
|
||||
/// DeadSymbols - A scratch set used to record the set of symbols that
|
||||
/// were just marked dead by a call to GRStateManager::RemoveDeadBindings.
|
||||
GRStateManager::DeadSymbolsTy DeadSymbols;
|
||||
|
||||
/// 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;
|
||||
|
||||
public:
|
||||
typedef llvm::SmallPtrSet<NodeTy*,2> UndefBranchesTy;
|
||||
typedef llvm::SmallPtrSet<NodeTy*,2> UndefStoresTy;
|
||||
typedef llvm::SmallPtrSet<NodeTy*,2> BadDerefTy;
|
||||
typedef llvm::SmallPtrSet<NodeTy*,2> BadCallsTy;
|
||||
typedef llvm::SmallPtrSet<NodeTy*,2> UndefReceiversTy;
|
||||
typedef llvm::DenseMap<NodeTy*, Expr*> UndefArgsTy;
|
||||
typedef llvm::SmallPtrSet<NodeTy*,2> BadDividesTy;
|
||||
typedef llvm::SmallPtrSet<NodeTy*,2> NoReturnCallsTy;
|
||||
typedef llvm::SmallPtrSet<NodeTy*,2> UndefResultsTy;
|
||||
typedef llvm::SmallPtrSet<NodeTy*,2> RetsStackAddrTy;
|
||||
|
||||
protected:
|
||||
|
||||
/// RetsStackAddr - Nodes in the ExplodedGraph that result from returning
|
||||
/// the address of a stack variable.
|
||||
RetsStackAddrTy RetsStackAddr;
|
||||
|
||||
/// UndefBranches - Nodes in the ExplodedGraph that result from
|
||||
/// taking a branch based on an undefined value.
|
||||
UndefBranchesTy UndefBranches;
|
||||
|
||||
/// UndefStores - Sinks in the ExplodedGraph that result from
|
||||
/// making a store to an undefined lvalue.
|
||||
UndefStoresTy UndefStores;
|
||||
|
||||
/// NoReturnCalls - Sinks in the ExplodedGraph that result from
|
||||
// calling a function with the attribute "noreturn".
|
||||
NoReturnCallsTy NoReturnCalls;
|
||||
|
||||
/// ImplicitNullDeref - Nodes in the ExplodedGraph that result from
|
||||
/// taking a dereference on a symbolic pointer that MAY be NULL.
|
||||
BadDerefTy ImplicitNullDeref;
|
||||
|
||||
/// ExplicitNullDeref - Nodes in the ExplodedGraph that result from
|
||||
/// taking a dereference on a symbolic pointer that MUST be NULL.
|
||||
BadDerefTy ExplicitNullDeref;
|
||||
|
||||
/// UnitDeref - Nodes in the ExplodedGraph that result from
|
||||
/// taking a dereference on an undefined value.
|
||||
BadDerefTy UndefDeref;
|
||||
|
||||
/// ImplicitBadDivides - Nodes in the ExplodedGraph that result from
|
||||
/// evaluating a divide or modulo operation where the denominator
|
||||
/// MAY be zero.
|
||||
BadDividesTy ImplicitBadDivides;
|
||||
|
||||
/// ExplicitBadDivides - Nodes in the ExplodedGraph that result from
|
||||
/// evaluating a divide or modulo operation where the denominator
|
||||
/// MUST be zero or undefined.
|
||||
BadDividesTy ExplicitBadDivides;
|
||||
|
||||
/// UndefResults - Nodes in the ExplodedGraph where the operands are defined
|
||||
/// by the result is not. Excludes divide-by-zero errors.
|
||||
UndefResultsTy UndefResults;
|
||||
|
||||
/// BadCalls - Nodes in the ExplodedGraph resulting from calls to function
|
||||
/// pointers that are NULL (or other constants) or Undefined.
|
||||
BadCallsTy BadCalls;
|
||||
|
||||
/// UndefReceiver - Nodes in the ExplodedGraph resulting from message
|
||||
/// ObjC message expressions where the receiver is undefined (uninitialized).
|
||||
UndefReceiversTy 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;
|
||||
|
||||
public:
|
||||
GRExprEngine(CFG& cfg, Decl& CD, ASTContext& Ctx, LiveVariables& L);
|
||||
~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 RetsStackAddrTy::iterator ret_stackaddr_iterator;
|
||||
ret_stackaddr_iterator ret_stackaddr_begin() { return RetsStackAddr.begin(); }
|
||||
ret_stackaddr_iterator ret_stackaddr_end() { return RetsStackAddr.end(); }
|
||||
|
||||
typedef UndefBranchesTy::iterator undef_branch_iterator;
|
||||
undef_branch_iterator undef_branches_begin() { return UndefBranches.begin(); }
|
||||
undef_branch_iterator undef_branches_end() { return UndefBranches.end(); }
|
||||
|
||||
typedef BadDerefTy::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 BadDerefTy::iterator undef_deref_iterator;
|
||||
undef_deref_iterator undef_derefs_begin() { return UndefDeref.begin(); }
|
||||
undef_deref_iterator undef_derefs_end() { return UndefDeref.end(); }
|
||||
|
||||
typedef BadDividesTy::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 UndefResultsTy::iterator undef_result_iterator;
|
||||
undef_result_iterator undef_results_begin() { return UndefResults.begin(); }
|
||||
undef_result_iterator undef_results_end() { return UndefResults.end(); }
|
||||
|
||||
typedef BadCallsTy::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 UndefReceiversTy::iterator undef_receivers_iterator;
|
||||
|
||||
undef_receivers_iterator undef_receivers_begin() {
|
||||
return UndefReceivers.begin();
|
||||
}
|
||||
|
||||
undef_receivers_iterator undef_receivers_end() {
|
||||
return UndefReceivers.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(Expr* 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);
|
||||
}
|
||||
|
||||
GRStateManager& getStateManager() { return StateMgr; }
|
||||
const GRStateManager& getStateManger() const { return StateMgr; }
|
||||
|
||||
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* SetRVal(const GRState* St, Expr* Ex, RVal V) {
|
||||
return StateMgr.SetRVal(St, Ex, V);
|
||||
}
|
||||
|
||||
const GRState* SetRVal(const GRState* St, const Expr* Ex, RVal V) {
|
||||
return SetRVal(St, const_cast<Expr*>(Ex), V);
|
||||
}
|
||||
|
||||
LVal getLVal(VarDecl* V) {
|
||||
return getStateManager().getLVal(V);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
const GRState* SetBlkExprRVal(const GRState* St, Expr* Ex, RVal V) {
|
||||
return StateMgr.SetRVal(St, Ex, V, true, false);
|
||||
}
|
||||
|
||||
const GRState* SetRVal(const GRState* St, LVal LV, RVal V) {
|
||||
return StateMgr.SetRVal(St, LV, V);
|
||||
}
|
||||
|
||||
RVal GetRVal(const GRState* St, Expr* Ex) {
|
||||
return StateMgr.GetRVal(St, Ex);
|
||||
}
|
||||
|
||||
RVal GetRVal(const GRState* St, const Expr* Ex) {
|
||||
return GetRVal(St, const_cast<Expr*>(Ex));
|
||||
}
|
||||
|
||||
RVal GetBlkExprRVal(const GRState* St, Expr* Ex) {
|
||||
return StateMgr.GetBlkExprRVal(St, Ex);
|
||||
}
|
||||
|
||||
RVal GetRVal(const GRState* St, LVal LV, QualType T = QualType()) {
|
||||
return StateMgr.GetRVal(St, LV, T);
|
||||
}
|
||||
|
||||
inline NonLVal MakeConstantVal(uint64_t X, Expr* Ex) {
|
||||
return NonLVal::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, RVal Cond, bool Assumption,
|
||||
bool& isFeasible) {
|
||||
return StateMgr.Assume(St, Cond, Assumption, isFeasible);
|
||||
}
|
||||
|
||||
const GRState* Assume(const GRState* St, LVal Cond, bool Assumption,
|
||||
bool& isFeasible) {
|
||||
return StateMgr.Assume(St, Cond, 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);
|
||||
|
||||
/// VisitLVal - Similar to Visit, but the specified expression is assummed
|
||||
/// to be evaluated under the context where it evaluates to an LVal. For
|
||||
/// example, if Ex is a DeclRefExpr, under Visit Ex would evaluate to the
|
||||
/// value bound to Ex in the symbolic state, while under VisitLVal it would
|
||||
/// evaluate to an LVal representing the location of the referred Decl.
|
||||
void VisitLVal(Expr* Ex, NodeTy* Pred, NodeSet& Dst);
|
||||
|
||||
/// VisitArraySubscriptExpr - Transfer function for array accesses.
|
||||
void VisitArraySubscriptExpr(ArraySubscriptExpr* Ex, NodeTy* Pred,
|
||||
NodeSet& Dst, bool asLVal);
|
||||
|
||||
/// 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);
|
||||
|
||||
/// VisitCast - Transfer function logic for all casts (implicit and explicit).
|
||||
void VisitCast(Expr* CastE, Expr* Ex, NodeTy* Pred, NodeSet& Dst);
|
||||
|
||||
/// VisitDeclRefExpr - Transfer function logic for DeclRefExprs.
|
||||
void VisitDeclRefExpr(DeclRefExpr* DR, NodeTy* Pred, NodeSet& Dst,
|
||||
bool asLval);
|
||||
|
||||
/// 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);
|
||||
|
||||
/// 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 asLVal);
|
||||
|
||||
/// 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);
|
||||
|
||||
/// VisitSizeOfAlignOfTypeExpr - Transfer function for sizeof(type).
|
||||
void VisitSizeOfAlignOfTypeExpr(SizeOfAlignOfTypeExpr* Ex, NodeTy* Pred,
|
||||
NodeSet& Dst);
|
||||
|
||||
/// VisitUnaryOperator - Transfer function logic for unary operators.
|
||||
void VisitUnaryOperator(UnaryOperator* B, NodeTy* Pred, NodeSet& Dst,
|
||||
bool asLVal);
|
||||
|
||||
bool CheckDivideZero(Expr* Ex, const GRState* St, NodeTy* Pred,
|
||||
RVal Denom);
|
||||
|
||||
RVal EvalCast(RVal X, QualType CastT) {
|
||||
if (X.isUnknownOrUndef())
|
||||
return X;
|
||||
|
||||
if (isa<LVal>(X))
|
||||
return getTF().EvalCast(*this, cast<LVal>(X), CastT);
|
||||
else
|
||||
return getTF().EvalCast(*this, cast<NonLVal>(X), CastT);
|
||||
}
|
||||
|
||||
RVal EvalMinus(UnaryOperator* U, RVal X) {
|
||||
return X.isValid() ? getTF().EvalMinus(*this, U, cast<NonLVal>(X)) : X;
|
||||
}
|
||||
|
||||
RVal EvalComplement(RVal X) {
|
||||
return X.isValid() ? getTF().EvalComplement(*this, cast<NonLVal>(X)) : X;
|
||||
}
|
||||
|
||||
RVal EvalBinOp(BinaryOperator::Opcode Op, NonLVal L, NonLVal R) {
|
||||
return R.isValid() ? getTF().DetermEvalBinOpNN(getStateManager(), Op, L, R)
|
||||
: R;
|
||||
}
|
||||
|
||||
RVal EvalBinOp(BinaryOperator::Opcode Op, NonLVal L, RVal R) {
|
||||
return R.isValid() ? getTF().DetermEvalBinOpNN(getStateManager(), Op, L,
|
||||
cast<NonLVal>(R)) : R;
|
||||
}
|
||||
|
||||
void EvalBinOp(ExplodedNodeSet<GRState>& Dst, Expr* Ex,
|
||||
BinaryOperator::Opcode Op, NonLVal L, NonLVal R,
|
||||
ExplodedNode<GRState>* Pred);
|
||||
|
||||
void EvalBinOp(GRStateSet& OStates, const GRState* St, Expr* Ex,
|
||||
BinaryOperator::Opcode Op, NonLVal L, NonLVal R);
|
||||
|
||||
RVal EvalBinOp(BinaryOperator::Opcode Op, RVal L, RVal R) {
|
||||
|
||||
if (L.isUndef() || R.isUndef())
|
||||
return UndefinedVal();
|
||||
|
||||
if (L.isUnknown() || R.isUnknown())
|
||||
return UnknownVal();
|
||||
|
||||
if (isa<LVal>(L)) {
|
||||
if (isa<LVal>(R))
|
||||
return getTF().EvalBinOp(*this, Op, cast<LVal>(L), cast<LVal>(R));
|
||||
else
|
||||
return getTF().EvalBinOp(*this, Op, cast<LVal>(L), cast<NonLVal>(R));
|
||||
}
|
||||
|
||||
if (isa<LVal>(R)) {
|
||||
// Support pointer arithmetic where the increment/decrement operand
|
||||
// is on the left and the pointer on the right.
|
||||
|
||||
assert (Op == BinaryOperator::Add || Op == BinaryOperator::Sub);
|
||||
|
||||
// Commute the operands.
|
||||
return getTF().EvalBinOp(*this, Op, cast<LVal>(R),
|
||||
cast<NonLVal>(L));
|
||||
}
|
||||
else
|
||||
return getTF().DetermEvalBinOpNN(getStateManager(), Op, cast<NonLVal>(L),
|
||||
cast<NonLVal>(R));
|
||||
}
|
||||
|
||||
|
||||
void EvalCall(NodeSet& Dst, CallExpr* CE, RVal 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,
|
||||
RVal TargetLV, RVal Val);
|
||||
|
||||
void EvalStore(NodeSet& Dst, Expr* E, Expr* StoreE, NodeTy* Pred,
|
||||
const GRState* St, RVal TargetLV, RVal 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, RVal location, bool CheckOnly = false);
|
||||
|
||||
const GRState* EvalLocation(Expr* Ex, NodeTy* Pred,
|
||||
const GRState* St, RVal location,
|
||||
bool isLoad = false);
|
||||
|
||||
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,584 +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 SymbolID, 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/RValues.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;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// 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 RVals.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// 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);
|
||||
}
|
||||
|
||||
RVal 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);
|
||||
}
|
||||
|
||||
// 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 RVal* 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> StMgr;
|
||||
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 RVals.
|
||||
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;
|
||||
|
||||
/// TF - Object that represents a bundle of transfer functions
|
||||
/// for manipulating and creating RVals.
|
||||
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, RVal V) {
|
||||
// return SetRVal(St, getLVal(D), V);
|
||||
// }
|
||||
|
||||
public:
|
||||
|
||||
typedef ConstraintManager* (*ConstraintManagerCreator)(GRStateManager&);
|
||||
typedef StoreManager* (*StoreManagerCreator)(GRStateManager&);
|
||||
|
||||
GRStateManager(ASTContext& Ctx,
|
||||
StoreManagerCreator CreateStoreManager,
|
||||
ConstraintManagerCreator CreateConstraintManager,
|
||||
llvm::BumpPtrAllocator& alloc, CFG& c, LiveVariables& L)
|
||||
: EnvMgr(alloc),
|
||||
ISetFactory(alloc),
|
||||
GDMFactory(alloc),
|
||||
BasicVals(Ctx, alloc),
|
||||
SymMgr(alloc),
|
||||
Alloc(alloc),
|
||||
cfg(c),
|
||||
Liveness(L) {
|
||||
StMgr.reset((*CreateStoreManager)(*this));
|
||||
ConstraintMgr.reset((*CreateConstraintManager)(*this));
|
||||
}
|
||||
|
||||
~GRStateManager();
|
||||
|
||||
const GRState* getInitialState();
|
||||
|
||||
ASTContext& getContext() { return BasicVals.getContext(); }
|
||||
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 StMgr->getRegionManager(); }
|
||||
|
||||
typedef StoreManager::DeadSymbolsTy DeadSymbolsTy;
|
||||
|
||||
const GRState* AddDecl(const GRState* St, const VarDecl* VD, Expr* Ex,
|
||||
unsigned Count);
|
||||
|
||||
const GRState* RemoveDeadBindings(const GRState* St, Stmt* Loc,
|
||||
const LiveVariables& Liveness,
|
||||
DeadSymbolsTy& DeadSyms);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
LVal getLVal(const VarDecl* D) {
|
||||
return StMgr->getLVal(D);
|
||||
}
|
||||
|
||||
// Methods that query & manipulate the Environment.
|
||||
|
||||
RVal GetRVal(const GRState* St, Expr* Ex) {
|
||||
return St->getEnvironment().GetRVal(Ex, BasicVals);
|
||||
}
|
||||
|
||||
RVal GetBlkExprRVal(const GRState* St, Expr* Ex) {
|
||||
return St->getEnvironment().GetBlkExprRVal(Ex, BasicVals);
|
||||
}
|
||||
|
||||
const GRState* SetRVal(const GRState* St, Expr* Ex, RVal V,
|
||||
bool isBlkExpr, bool Invalidate) {
|
||||
|
||||
const Environment& OldEnv = St->getEnvironment();
|
||||
Environment NewEnv = EnvMgr.SetRVal(OldEnv, Ex, V, isBlkExpr, Invalidate);
|
||||
|
||||
if (NewEnv == OldEnv)
|
||||
return St;
|
||||
|
||||
GRState NewSt = *St;
|
||||
NewSt.Env = NewEnv;
|
||||
return getPersistentState(NewSt);
|
||||
}
|
||||
|
||||
const GRState* SetRVal(const GRState* St, Expr* Ex, RVal 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 SetRVal(St, Ex, V, isBlkExpr, Invalidate);
|
||||
}
|
||||
|
||||
// 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) {
|
||||
StMgr->iterBindings(state->getStore(), F);
|
||||
}
|
||||
|
||||
|
||||
RVal GetRVal(const GRState* St, LVal LV, QualType T = QualType()) {
|
||||
return StMgr->GetRVal(St->getStore(), LV, T);
|
||||
}
|
||||
|
||||
void SetRVal(GRState& St, LVal LV, RVal V) {
|
||||
St.St = StMgr->SetRVal(St.St, LV, V);
|
||||
}
|
||||
|
||||
const GRState* SetRVal(const GRState* St, LVal LV, RVal V);
|
||||
|
||||
void Unbind(GRState& St, LVal LV) {
|
||||
St.St = StMgr->Remove(St.St, LV);
|
||||
}
|
||||
|
||||
const GRState* Unbind(const GRState* St, LVal LV);
|
||||
|
||||
const GRState* getPersistentState(GRState& Impl);
|
||||
|
||||
bool isEqual(const GRState* state, Expr* Ex, const llvm::APSInt& V);
|
||||
bool isEqual(const GRState* state, Expr* Ex, uint64_t);
|
||||
|
||||
// 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* 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);
|
||||
}
|
||||
|
||||
const GRState* Assume(const GRState* St, RVal Cond, bool Assumption,
|
||||
bool& isFeasible) {
|
||||
return ConstraintMgr->Assume(St, Cond, Assumption, isFeasible);
|
||||
}
|
||||
|
||||
const GRState* AddNE(const GRState* St, SymbolID sym, const llvm::APSInt& V) {
|
||||
return ConstraintMgr->AddNE(St, sym, V);
|
||||
}
|
||||
|
||||
const llvm::APSInt* getSymVal(const GRState* St, SymbolID sym) {
|
||||
return ConstraintMgr->getSymVal(St, sym);
|
||||
}
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// 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; }
|
||||
|
||||
RVal GetRVal(Expr* Ex) {
|
||||
return Mgr->GetRVal(St, Ex);
|
||||
}
|
||||
|
||||
RVal GetBlkExprRVal(Expr* Ex) {
|
||||
return Mgr->GetBlkExprRVal(St, Ex);
|
||||
}
|
||||
|
||||
RVal GetRVal(LVal LV, QualType T = QualType()) {
|
||||
return Mgr->GetRVal(St, LV, T);
|
||||
}
|
||||
|
||||
GRStateRef SetRVal(Expr* Ex, RVal V, bool isBlkExpr, bool Invalidate) {
|
||||
return GRStateRef(Mgr->SetRVal(St, Ex, V, isBlkExpr, Invalidate), *Mgr);
|
||||
}
|
||||
|
||||
GRStateRef SetRVal(Expr* Ex, RVal V, bool Invalidate = true) {
|
||||
return GRStateRef(Mgr->SetRVal(St, Ex, V, Invalidate), *Mgr);
|
||||
}
|
||||
|
||||
GRStateRef SetRVal(LVal LV, RVal V) {
|
||||
GRState StImpl = *St;
|
||||
Mgr->SetRVal(StImpl, LV, V);
|
||||
return GRStateRef(Mgr->getPersistentState(StImpl), *Mgr);
|
||||
}
|
||||
|
||||
GRStateRef Unbind(LVal LV) {
|
||||
return GRStateRef(Mgr->Unbind(St, LV), *Mgr);
|
||||
}
|
||||
|
||||
GRStateRef AddNE(SymbolID sym, const llvm::APSInt& V) {
|
||||
return GRStateRef(Mgr->AddNE(St, sym, V), *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 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);
|
||||
}
|
||||
|
||||
// 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,67 +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;
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
template <typename T> struct GRStatePartialTrait;
|
||||
|
||||
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;
|
||||
}
|
||||
};
|
||||
} // end clang namespace
|
||||
|
||||
#endif
|
||||
@@ -1,132 +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/RValues.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 RVal DetermEvalBinOpNN(GRStateManager& StateMgr,
|
||||
BinaryOperator::Opcode Op,
|
||||
NonLVal L, NonLVal R) {
|
||||
return UnknownVal();
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
GRTransferFuncs() {}
|
||||
virtual ~GRTransferFuncs() {}
|
||||
|
||||
virtual void RegisterPrinters(std::vector<GRState::Printer*>& Printers) {}
|
||||
virtual void RegisterChecks(GRExprEngine& Eng);
|
||||
|
||||
// Casts.
|
||||
|
||||
virtual RVal EvalCast(GRExprEngine& Engine, NonLVal V, QualType CastT) =0;
|
||||
virtual RVal EvalCast(GRExprEngine& Engine, LVal V, QualType CastT) = 0;
|
||||
|
||||
// Unary Operators.
|
||||
|
||||
virtual RVal EvalMinus(GRExprEngine& Engine, UnaryOperator* U, NonLVal X) = 0;
|
||||
|
||||
virtual RVal EvalComplement(GRExprEngine& Engine, NonLVal X) = 0;
|
||||
|
||||
// Binary Operators.
|
||||
virtual void EvalBinOpNN(GRStateSet& OStates, GRStateManager& StateMgr,
|
||||
const GRState* St, Expr* Ex,
|
||||
BinaryOperator::Opcode Op, NonLVal L, NonLVal R);
|
||||
|
||||
virtual RVal EvalBinOp(GRExprEngine& Engine, BinaryOperator::Opcode Op,
|
||||
LVal L, LVal R) = 0;
|
||||
|
||||
// Pointer arithmetic.
|
||||
|
||||
virtual RVal EvalBinOp(GRExprEngine& Engine, BinaryOperator::Opcode Op,
|
||||
LVal L, NonLVal R) = 0;
|
||||
|
||||
// Calls.
|
||||
|
||||
virtual void EvalCall(ExplodedNodeSet<GRState>& Dst,
|
||||
GRExprEngine& Engine,
|
||||
GRStmtNodeBuilder<GRState>& Builder,
|
||||
CallExpr* CE, RVal 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 LVal.
|
||||
virtual void EvalStore(ExplodedNodeSet<GRState>& Dst,
|
||||
GRExprEngine& Engine,
|
||||
GRStmtNodeBuilder<GRState>& Builder,
|
||||
Expr* E, ExplodedNode<GRState>* Pred,
|
||||
const GRState* St, RVal TargetLV, RVal 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* St,
|
||||
const GRStateManager::DeadSymbolsTy& Dead) {}
|
||||
|
||||
// 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,
|
||||
RVal Cond, bool Assumption,
|
||||
bool& isFeasible) {
|
||||
return St;
|
||||
}
|
||||
};
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
#endif
|
||||
@@ -1,74 +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();
|
||||
};
|
||||
} // end clang namespace
|
||||
#endif
|
||||
@@ -1,267 +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 "llvm/Support/Casting.h"
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/DeclObjC.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,
|
||||
// Typed regions.
|
||||
BEG_TYPED_REGIONS,
|
||||
VarRegionKind, FieldRegionKind, ObjCIvarRegionKind,
|
||||
AnonTypedRegionKind,
|
||||
END_TYPED_REGIONS };
|
||||
private:
|
||||
const Kind kind;
|
||||
|
||||
protected:
|
||||
MemRegion(Kind k) : kind(k) {}
|
||||
virtual ~MemRegion();
|
||||
|
||||
public:
|
||||
// virtual MemExtent getExtent(MemRegionManager& mrm) const = 0;
|
||||
virtual const MemRegion* getSuperRegion() 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(); }
|
||||
|
||||
const MemRegion* getSuperRegion() const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
//static void ProfileRegion(llvm::FoldingSetNodeID& ID);
|
||||
void Profile(llvm::FoldingSetNodeID& ID) const;
|
||||
|
||||
static bool classof(const MemRegion* R) {
|
||||
return R->getKind() == MemSpaceRegionKind;
|
||||
}
|
||||
};
|
||||
|
||||
/// TypedRegion - An abstract class representing regions that are typed.
|
||||
class TypedRegion : public MemRegion {
|
||||
protected:
|
||||
const MemRegion* superRegion;
|
||||
|
||||
TypedRegion(const MemRegion* sReg, Kind k)
|
||||
: MemRegion(k), superRegion(sReg) {};
|
||||
|
||||
public:
|
||||
virtual QualType getType() const = 0;
|
||||
|
||||
// MemExtent getExtent(MemRegionManager& mrm) const;
|
||||
const MemRegion* getSuperRegion() const {
|
||||
return superRegion;
|
||||
}
|
||||
|
||||
static bool classof(const MemRegion* R) {
|
||||
unsigned k = R->getKind();
|
||||
return k > BEG_TYPED_REGIONS && k < END_TYPED_REGIONS;
|
||||
}
|
||||
};
|
||||
|
||||
/// AnonTypedRegion - An "anonymous" region that simply types a chunk
|
||||
/// of memory.
|
||||
class AnonTypedRegion : public TypedRegion {
|
||||
QualType T;
|
||||
|
||||
friend class MemRegionManager;
|
||||
|
||||
AnonTypedRegion(QualType t, MemRegion* sreg)
|
||||
: TypedRegion(sreg, AnonTypedRegionKind), T(t) {}
|
||||
|
||||
static void ProfileRegion(llvm::FoldingSetNodeID& ID, QualType T,
|
||||
const MemRegion* superRegion);
|
||||
|
||||
public:
|
||||
QualType getType() const { return T; }
|
||||
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID& ID) const;
|
||||
|
||||
static bool classof(const MemRegion* R) {
|
||||
return R->getKind() == AnonTypedRegionKind;
|
||||
}
|
||||
};
|
||||
|
||||
class DeclRegion : public TypedRegion {
|
||||
protected:
|
||||
const Decl* D;
|
||||
|
||||
DeclRegion(const Decl* d, MemRegion* sReg, Kind k)
|
||||
: TypedRegion(sReg, k), D(d) {}
|
||||
|
||||
static void ProfileRegion(llvm::FoldingSetNodeID& ID, const Decl* D,
|
||||
const MemRegion* superRegion, Kind k);
|
||||
|
||||
public:
|
||||
void Profile(llvm::FoldingSetNodeID& ID) const;
|
||||
};
|
||||
|
||||
class VarRegion : public DeclRegion {
|
||||
friend class MemRegionManager;
|
||||
|
||||
VarRegion(const VarDecl* vd, 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 getType() const { return 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, MemRegion* sReg)
|
||||
: DeclRegion(fd, sReg, FieldRegionKind) {}
|
||||
|
||||
static void ProfileRegion(llvm::FoldingSetNodeID& ID, FieldDecl* FD,
|
||||
const MemRegion* superRegion) {
|
||||
DeclRegion::ProfileRegion(ID, FD, superRegion, FieldRegionKind);
|
||||
}
|
||||
|
||||
public:
|
||||
const FieldDecl* getDecl() const { return cast<FieldDecl>(D); }
|
||||
QualType getType() const { return getDecl()->getType(); }
|
||||
|
||||
static bool classof(const MemRegion* R) {
|
||||
return R->getKind() == FieldRegionKind;
|
||||
}
|
||||
};
|
||||
|
||||
class ObjCIvarRegion : public DeclRegion {
|
||||
|
||||
friend class MemRegionManager;
|
||||
|
||||
ObjCIvarRegion(const ObjCIvarDecl* ivd, 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 getType() const { return getDecl()->getType(); }
|
||||
|
||||
static bool classof(const MemRegion* R) {
|
||||
return R->getKind() == ObjCIvarRegionKind;
|
||||
}
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// MemRegionManager - Factory object for creating regions.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
class MemRegionManager {
|
||||
llvm::BumpPtrAllocator& A;
|
||||
llvm::FoldingSet<MemRegion> Regions;
|
||||
|
||||
MemSpaceRegion* globals;
|
||||
MemSpaceRegion* stack;
|
||||
MemSpaceRegion* heap;
|
||||
|
||||
public:
|
||||
MemRegionManager(llvm::BumpPtrAllocator& a)
|
||||
: A(a), globals(0), stack(0), heap(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();
|
||||
|
||||
/// getVarRegion - Retrieve or create the memory region associated with
|
||||
/// a specified VarDecl. 'superRegion' corresponds to the containing
|
||||
/// memory region, and 'off' is the offset within the containing region.
|
||||
VarRegion* getVarRegion(const VarDecl* vd, MemRegion* superRegion);
|
||||
|
||||
VarRegion* getVarRegion(const VarDecl* vd) {
|
||||
return getVarRegion(vd, vd->hasLocalStorage() ? getStackRegion()
|
||||
: getGlobalsRegion());
|
||||
}
|
||||
|
||||
/// 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, 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,
|
||||
MemRegion* superRegion);
|
||||
|
||||
bool hasStackStorage(const MemRegion* R);
|
||||
|
||||
private:
|
||||
MemSpaceRegion* LazyAllocate(MemSpaceRegion*& region);
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // end clang namespace
|
||||
#endif
|
||||
@@ -1,513 +0,0 @@
|
||||
//== RValues.h - Abstract RValues for Path-Sens. Value Tracking -*- 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 RVal, LVal, and NonLVal, classes that represent
|
||||
// abstract r-values for use with path-sensitive value tracking.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSIS_RVALUE_H
|
||||
#define LLVM_CLANG_ANALYSIS_RVALUE_H
|
||||
|
||||
#include "clang/Analysis/PathSensitive/BasicValueFactory.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
|
||||
//==------------------------------------------------------------------------==//
|
||||
// Base RVal types.
|
||||
//==------------------------------------------------------------------------==//
|
||||
|
||||
namespace clang {
|
||||
|
||||
class MemRegion;
|
||||
class GRStateManager;
|
||||
|
||||
class RVal {
|
||||
public:
|
||||
enum BaseKind { UndefinedKind, UnknownKind, LValKind, NonLValKind };
|
||||
enum { BaseBits = 2, BaseMask = 0x3 };
|
||||
|
||||
protected:
|
||||
void* Data;
|
||||
unsigned Kind;
|
||||
|
||||
protected:
|
||||
RVal(const void* d, bool isLVal, unsigned ValKind)
|
||||
: Data(const_cast<void*>(d)),
|
||||
Kind((isLVal ? LValKind : NonLValKind) | (ValKind << BaseBits)) {}
|
||||
|
||||
explicit RVal(BaseKind k, void* D = NULL)
|
||||
: Data(D), Kind(k) {}
|
||||
|
||||
public:
|
||||
~RVal() {};
|
||||
|
||||
/// BufferTy - A temporary buffer to hold a set of RVals.
|
||||
typedef llvm::SmallVector<RVal,5> BufferTy;
|
||||
|
||||
inline unsigned getRawKind() const { return Kind; }
|
||||
inline BaseKind getBaseKind() const { return (BaseKind) (Kind & BaseMask); }
|
||||
inline unsigned getSubKind() const { return (Kind & ~BaseMask) >> BaseBits; }
|
||||
|
||||
inline void Profile(llvm::FoldingSetNodeID& ID) const {
|
||||
ID.AddInteger((unsigned) getRawKind());
|
||||
ID.AddPointer(reinterpret_cast<void*>(Data));
|
||||
}
|
||||
|
||||
inline bool operator==(const RVal& R) const {
|
||||
return getRawKind() == R.getRawKind() && Data == R.Data;
|
||||
}
|
||||
|
||||
|
||||
inline bool operator!=(const RVal& R) const {
|
||||
return !(*this == R);
|
||||
}
|
||||
|
||||
static RVal GetSymbolValue(SymbolManager& SymMgr, VarDecl *D);
|
||||
|
||||
inline bool isUnknown() const {
|
||||
return getRawKind() == UnknownKind;
|
||||
}
|
||||
|
||||
inline bool isUndef() const {
|
||||
return getRawKind() == UndefinedKind;
|
||||
}
|
||||
|
||||
inline bool isUnknownOrUndef() const {
|
||||
return getRawKind() <= UnknownKind;
|
||||
}
|
||||
|
||||
inline bool isValid() const {
|
||||
return getRawKind() > UnknownKind;
|
||||
}
|
||||
|
||||
bool isZeroConstant() const;
|
||||
|
||||
void print(std::ostream& OS) const;
|
||||
void printStdErr() const;
|
||||
|
||||
typedef const SymbolID* symbol_iterator;
|
||||
symbol_iterator symbol_begin() const;
|
||||
symbol_iterator symbol_end() const;
|
||||
|
||||
static RVal MakeVal(GRStateManager& SMgr, DeclRefExpr* E);
|
||||
|
||||
// Implement isa<T> support.
|
||||
static inline bool classof(const RVal*) { return true; }
|
||||
};
|
||||
|
||||
class UnknownVal : public RVal {
|
||||
public:
|
||||
UnknownVal() : RVal(UnknownKind) {}
|
||||
|
||||
static inline bool classof(const RVal* V) {
|
||||
return V->getBaseKind() == UnknownKind;
|
||||
}
|
||||
};
|
||||
|
||||
class UndefinedVal : public RVal {
|
||||
public:
|
||||
UndefinedVal() : RVal(UndefinedKind) {}
|
||||
UndefinedVal(void* D) : RVal(UndefinedKind, D) {}
|
||||
|
||||
static inline bool classof(const RVal* V) {
|
||||
return V->getBaseKind() == UndefinedKind;
|
||||
}
|
||||
|
||||
void* getData() const { return Data; }
|
||||
};
|
||||
|
||||
class NonLVal : public RVal {
|
||||
protected:
|
||||
NonLVal(unsigned SubKind, const void* d) : RVal(d, false, SubKind) {}
|
||||
|
||||
public:
|
||||
void print(std::ostream& Out) const;
|
||||
|
||||
// Utility methods to create NonLVals.
|
||||
static NonLVal MakeVal(BasicValueFactory& BasicVals, uint64_t X, QualType T);
|
||||
|
||||
static NonLVal MakeVal(BasicValueFactory& BasicVals, IntegerLiteral* I);
|
||||
|
||||
static NonLVal MakeIntTruthVal(BasicValueFactory& BasicVals, bool b);
|
||||
|
||||
// Implement isa<T> support.
|
||||
static inline bool classof(const RVal* V) {
|
||||
return V->getBaseKind() == NonLValKind;
|
||||
}
|
||||
};
|
||||
|
||||
class LVal : public RVal {
|
||||
protected:
|
||||
LVal(unsigned SubKind, const void* D)
|
||||
: RVal(const_cast<void*>(D), true, SubKind) {}
|
||||
|
||||
// Equality operators.
|
||||
NonLVal EQ(BasicValueFactory& BasicVals, const LVal& R) const;
|
||||
NonLVal NE(BasicValueFactory& BasicVals, const LVal& R) const;
|
||||
|
||||
public:
|
||||
void print(std::ostream& Out) const;
|
||||
|
||||
static LVal MakeVal(AddrLabelExpr* E);
|
||||
|
||||
static LVal MakeVal(StringLiteral* S);
|
||||
|
||||
// Implement isa<T> support.
|
||||
static inline bool classof(const RVal* V) {
|
||||
return V->getBaseKind() == LValKind;
|
||||
}
|
||||
|
||||
static inline bool IsLValType(QualType T) {
|
||||
return T->isPointerType() || T->isObjCQualifiedIdType()
|
||||
|| T->isBlockPointerType();
|
||||
}
|
||||
};
|
||||
|
||||
//==------------------------------------------------------------------------==//
|
||||
// Subclasses of NonLVal.
|
||||
//==------------------------------------------------------------------------==//
|
||||
|
||||
namespace nonlval {
|
||||
|
||||
enum Kind { ConcreteIntKind, SymbolValKind, SymIntConstraintValKind,
|
||||
LValAsIntegerKind };
|
||||
|
||||
class SymbolVal : public NonLVal {
|
||||
public:
|
||||
SymbolVal(unsigned SymID)
|
||||
: NonLVal(SymbolValKind, reinterpret_cast<void*>((uintptr_t) SymID)) {}
|
||||
|
||||
SymbolID getSymbol() const {
|
||||
return (SymbolID) reinterpret_cast<uintptr_t>(Data);
|
||||
}
|
||||
|
||||
static inline bool classof(const RVal* V) {
|
||||
return V->getBaseKind() == NonLValKind &&
|
||||
V->getSubKind() == SymbolValKind;
|
||||
}
|
||||
|
||||
static inline bool classof(const NonLVal* V) {
|
||||
return V->getSubKind() == SymbolValKind;
|
||||
}
|
||||
};
|
||||
|
||||
class SymIntConstraintVal : public NonLVal {
|
||||
public:
|
||||
SymIntConstraintVal(const SymIntConstraint& C)
|
||||
: NonLVal(SymIntConstraintValKind, reinterpret_cast<const void*>(&C)) {}
|
||||
|
||||
const SymIntConstraint& getConstraint() const {
|
||||
return *reinterpret_cast<SymIntConstraint*>(Data);
|
||||
}
|
||||
|
||||
static inline bool classof(const RVal* V) {
|
||||
return V->getBaseKind() == NonLValKind &&
|
||||
V->getSubKind() == SymIntConstraintValKind;
|
||||
}
|
||||
|
||||
static inline bool classof(const NonLVal* V) {
|
||||
return V->getSubKind() == SymIntConstraintValKind;
|
||||
}
|
||||
};
|
||||
|
||||
class ConcreteInt : public NonLVal {
|
||||
public:
|
||||
ConcreteInt(const llvm::APSInt& V) : NonLVal(ConcreteIntKind, &V) {}
|
||||
|
||||
const llvm::APSInt& getValue() const {
|
||||
return *static_cast<llvm::APSInt*>(Data);
|
||||
}
|
||||
|
||||
// Transfer functions for binary/unary operations on ConcreteInts.
|
||||
RVal EvalBinOp(BasicValueFactory& BasicVals, BinaryOperator::Opcode Op,
|
||||
const ConcreteInt& R) const;
|
||||
|
||||
ConcreteInt EvalComplement(BasicValueFactory& BasicVals) const;
|
||||
|
||||
ConcreteInt EvalMinus(BasicValueFactory& BasicVals, UnaryOperator* U) const;
|
||||
|
||||
// Implement isa<T> support.
|
||||
static inline bool classof(const RVal* V) {
|
||||
return V->getBaseKind() == NonLValKind &&
|
||||
V->getSubKind() == ConcreteIntKind;
|
||||
}
|
||||
|
||||
static inline bool classof(const NonLVal* V) {
|
||||
return V->getSubKind() == ConcreteIntKind;
|
||||
}
|
||||
};
|
||||
|
||||
class LValAsInteger : public NonLVal {
|
||||
LValAsInteger(const std::pair<RVal, uintptr_t>& data) :
|
||||
NonLVal(LValAsIntegerKind, &data) {
|
||||
assert (isa<LVal>(data.first));
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
LVal getLVal() const {
|
||||
return cast<LVal>(((std::pair<RVal, uintptr_t>*) Data)->first);
|
||||
}
|
||||
|
||||
const LVal& getPersistentLVal() const {
|
||||
const RVal& V = ((std::pair<RVal, uintptr_t>*) Data)->first;
|
||||
return cast<LVal>(V);
|
||||
}
|
||||
|
||||
unsigned getNumBits() const {
|
||||
return ((std::pair<RVal, unsigned>*) Data)->second;
|
||||
}
|
||||
|
||||
// Implement isa<T> support.
|
||||
static inline bool classof(const RVal* V) {
|
||||
return V->getBaseKind() == NonLValKind &&
|
||||
V->getSubKind() == LValAsIntegerKind;
|
||||
}
|
||||
|
||||
static inline bool classof(const NonLVal* V) {
|
||||
return V->getSubKind() == LValAsIntegerKind;
|
||||
}
|
||||
|
||||
static inline LValAsInteger Make(BasicValueFactory& Vals, LVal V,
|
||||
unsigned Bits) {
|
||||
return LValAsInteger(Vals.getPersistentRValWithData(V, Bits));
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace clang::nonlval
|
||||
|
||||
//==------------------------------------------------------------------------==//
|
||||
// Subclasses of LVal.
|
||||
//==------------------------------------------------------------------------==//
|
||||
|
||||
namespace lval {
|
||||
|
||||
enum Kind { SymbolValKind, GotoLabelKind, MemRegionKind, FuncValKind,
|
||||
ConcreteIntKind, StringLiteralValKind, FieldOffsetKind,
|
||||
ArrayOffsetKind };
|
||||
|
||||
class SymbolVal : public LVal {
|
||||
public:
|
||||
SymbolVal(unsigned SymID)
|
||||
: LVal(SymbolValKind, reinterpret_cast<void*>((uintptr_t) SymID)) {}
|
||||
|
||||
SymbolID getSymbol() const {
|
||||
return (SymbolID) reinterpret_cast<uintptr_t>(Data);
|
||||
}
|
||||
|
||||
static inline bool classof(const RVal* V) {
|
||||
return V->getBaseKind() == LValKind &&
|
||||
V->getSubKind() == SymbolValKind;
|
||||
}
|
||||
|
||||
static inline bool classof(const LVal* V) {
|
||||
return V->getSubKind() == SymbolValKind;
|
||||
}
|
||||
};
|
||||
|
||||
class GotoLabel : public LVal {
|
||||
public:
|
||||
GotoLabel(LabelStmt* Label) : LVal(GotoLabelKind, Label) {}
|
||||
|
||||
LabelStmt* getLabel() const {
|
||||
return static_cast<LabelStmt*>(Data);
|
||||
}
|
||||
|
||||
static inline bool classof(const RVal* V) {
|
||||
return V->getBaseKind() == LValKind &&
|
||||
V->getSubKind() == GotoLabelKind;
|
||||
}
|
||||
|
||||
static inline bool classof(const LVal* V) {
|
||||
return V->getSubKind() == GotoLabelKind;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class MemRegionVal : public LVal {
|
||||
public:
|
||||
MemRegionVal(const MemRegion* r) : LVal(MemRegionKind, r) {}
|
||||
|
||||
MemRegion* getRegion() const {
|
||||
return static_cast<MemRegion*>(Data);
|
||||
}
|
||||
|
||||
inline bool operator==(const MemRegionVal& R) const {
|
||||
return getRegion() == R.getRegion();
|
||||
}
|
||||
|
||||
inline bool operator!=(const MemRegionVal& R) const {
|
||||
return getRegion() != R.getRegion();
|
||||
}
|
||||
|
||||
// Implement isa<T> support.
|
||||
static inline bool classof(const RVal* V) {
|
||||
return V->getBaseKind() == LValKind &&
|
||||
V->getSubKind() == MemRegionKind;
|
||||
}
|
||||
|
||||
static inline bool classof(const LVal* V) {
|
||||
return V->getSubKind() == MemRegionKind;
|
||||
}
|
||||
};
|
||||
|
||||
class FuncVal : public LVal {
|
||||
public:
|
||||
FuncVal(const FunctionDecl* fd) : LVal(FuncValKind, fd) {}
|
||||
|
||||
FunctionDecl* getDecl() const {
|
||||
return static_cast<FunctionDecl*>(Data);
|
||||
}
|
||||
|
||||
inline bool operator==(const FuncVal& R) const {
|
||||
return getDecl() == R.getDecl();
|
||||
}
|
||||
|
||||
inline bool operator!=(const FuncVal& R) const {
|
||||
return getDecl() != R.getDecl();
|
||||
}
|
||||
|
||||
// Implement isa<T> support.
|
||||
static inline bool classof(const RVal* V) {
|
||||
return V->getBaseKind() == LValKind &&
|
||||
V->getSubKind() == FuncValKind;
|
||||
}
|
||||
|
||||
static inline bool classof(const LVal* V) {
|
||||
return V->getSubKind() == FuncValKind;
|
||||
}
|
||||
};
|
||||
|
||||
class ConcreteInt : public LVal {
|
||||
public:
|
||||
ConcreteInt(const llvm::APSInt& V) : LVal(ConcreteIntKind, &V) {}
|
||||
|
||||
const llvm::APSInt& getValue() const {
|
||||
return *static_cast<llvm::APSInt*>(Data);
|
||||
}
|
||||
|
||||
// Transfer functions for binary/unary operations on ConcreteInts.
|
||||
RVal EvalBinOp(BasicValueFactory& BasicVals, BinaryOperator::Opcode Op,
|
||||
const ConcreteInt& R) const;
|
||||
|
||||
// Implement isa<T> support.
|
||||
static inline bool classof(const RVal* V) {
|
||||
return V->getBaseKind() == LValKind &&
|
||||
V->getSubKind() == ConcreteIntKind;
|
||||
}
|
||||
|
||||
static inline bool classof(const LVal* V) {
|
||||
return V->getSubKind() == ConcreteIntKind;
|
||||
}
|
||||
};
|
||||
|
||||
class StringLiteralVal : public LVal {
|
||||
public:
|
||||
StringLiteralVal(StringLiteral* L) : LVal(StringLiteralValKind, L) {}
|
||||
|
||||
StringLiteral* getLiteral() const { return (StringLiteral*) Data; }
|
||||
|
||||
// Implement isa<T> support.
|
||||
static inline bool classof(const RVal* V) {
|
||||
return V->getBaseKind() == LValKind &&
|
||||
V->getSubKind() == StringLiteralValKind;
|
||||
}
|
||||
|
||||
static inline bool classof(const LVal* V) {
|
||||
return V->getSubKind() == StringLiteralValKind;
|
||||
}
|
||||
};
|
||||
|
||||
class FieldOffset : public LVal {
|
||||
FieldOffset(const std::pair<RVal, uintptr_t>& data)
|
||||
: LVal(FieldOffsetKind, &data) {}
|
||||
|
||||
public:
|
||||
|
||||
LVal getBase() const {
|
||||
return reinterpret_cast<const std::pair<LVal,uintptr_t>*> (Data)->first;
|
||||
}
|
||||
|
||||
const LVal& getPersistentBase() const {
|
||||
return reinterpret_cast<const std::pair<LVal,uintptr_t>*> (Data)->first;
|
||||
}
|
||||
|
||||
|
||||
FieldDecl* getFieldDecl() const {
|
||||
return (FieldDecl*)
|
||||
reinterpret_cast<const std::pair<LVal,uintptr_t>*> (Data)->second;
|
||||
}
|
||||
|
||||
// Implement isa<T> support.
|
||||
static inline bool classof(const RVal* V) {
|
||||
return V->getBaseKind() == LValKind &&
|
||||
V->getSubKind() == FieldOffsetKind;
|
||||
}
|
||||
|
||||
static inline bool classof(const LVal* V) {
|
||||
return V->getSubKind() == FieldOffsetKind;
|
||||
}
|
||||
|
||||
static inline RVal Make(BasicValueFactory& Vals, RVal Base, FieldDecl* D) {
|
||||
|
||||
if (Base.isUnknownOrUndef())
|
||||
return Base;
|
||||
|
||||
return FieldOffset(Vals.getPersistentRValWithData(cast<LVal>(Base),
|
||||
(uintptr_t) D));
|
||||
}
|
||||
};
|
||||
|
||||
class ArrayOffset : public LVal {
|
||||
ArrayOffset(const std::pair<RVal,RVal>& data) : LVal(ArrayOffsetKind,&data) {}
|
||||
public:
|
||||
|
||||
LVal getBase() const {
|
||||
return reinterpret_cast<const std::pair<LVal,RVal>*> (Data)->first;
|
||||
}
|
||||
|
||||
const LVal& getPersistentBase() const {
|
||||
return reinterpret_cast<const std::pair<LVal,RVal>*> (Data)->first;
|
||||
}
|
||||
|
||||
RVal getOffset() const {
|
||||
return reinterpret_cast<const std::pair<LVal,RVal>*> (Data)->second;
|
||||
}
|
||||
|
||||
const RVal& getPersistentOffset() const {
|
||||
return reinterpret_cast<const std::pair<LVal,RVal>*> (Data)->second;
|
||||
}
|
||||
|
||||
|
||||
// Implement isa<T> support.
|
||||
static inline bool classof(const RVal* V) {
|
||||
return V->getBaseKind() == LValKind &&
|
||||
V->getSubKind() == ArrayOffsetKind;
|
||||
}
|
||||
|
||||
static inline bool classof(const LVal* V) {
|
||||
return V->getSubKind() == ArrayOffsetKind;
|
||||
}
|
||||
|
||||
static inline RVal Make(BasicValueFactory& Vals, RVal Base, RVal Offset) {
|
||||
|
||||
if (Base.isUnknownOrUndef())
|
||||
return Base;
|
||||
|
||||
if (Offset.isUndef())
|
||||
return Offset;
|
||||
|
||||
return ArrayOffset(Vals.getPersistentRValPair(cast<LVal>(Base), Offset));
|
||||
}
|
||||
};
|
||||
|
||||
} // end clang::lval namespace
|
||||
} // end clang namespace
|
||||
|
||||
#endif
|
||||
@@ -1,73 +0,0 @@
|
||||
//== Store.h - Interface for maps from Locations to 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 types Store and StoreManager.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSIS_STORE_H
|
||||
#define LLVM_CLANG_ANALYSIS_STORE_H
|
||||
|
||||
#include "clang/Analysis/PathSensitive/RValues.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/ADT/SmallSet.h"
|
||||
#include "llvm/ADT/DenseSet.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include <iosfwd>
|
||||
|
||||
namespace clang {
|
||||
|
||||
typedef const void* Store;
|
||||
|
||||
class GRStateManager;
|
||||
class LiveVariables;
|
||||
class Stmt;
|
||||
class MemRegion;
|
||||
class MemRegionManager;
|
||||
|
||||
class StoreManager {
|
||||
public:
|
||||
typedef llvm::SmallSet<SymbolID, 20> LiveSymbolsTy;
|
||||
typedef llvm::DenseSet<SymbolID> DeadSymbolsTy;
|
||||
|
||||
virtual ~StoreManager() {}
|
||||
virtual RVal GetRVal(Store St, LVal LV, QualType T = QualType()) = 0;
|
||||
virtual Store SetRVal(Store St, LVal LV, RVal V) = 0;
|
||||
virtual Store Remove(Store St, LVal LV) = 0;
|
||||
virtual Store getInitialStore() = 0;
|
||||
virtual MemRegionManager& getRegionManager() = 0;
|
||||
virtual LVal getLVal(const VarDecl* VD) = 0;
|
||||
virtual Store
|
||||
RemoveDeadBindings(Store store, Stmt* Loc, const LiveVariables& Live,
|
||||
llvm::SmallVectorImpl<const MemRegion*>& RegionRoots,
|
||||
LiveSymbolsTy& LSymbols, DeadSymbolsTy& DSymbols) = 0;
|
||||
|
||||
virtual Store AddDecl(Store store,
|
||||
const VarDecl* VD, Expr* Ex,
|
||||
RVal InitVal = UndefinedVal(), unsigned Count = 0) = 0;
|
||||
|
||||
virtual void print(Store store, std::ostream& Out,
|
||||
const char* nl, const char *sep) = 0;
|
||||
|
||||
class BindingsHandler {
|
||||
public:
|
||||
virtual ~BindingsHandler();
|
||||
virtual bool HandleBinding(StoreManager& SMgr, Store store,
|
||||
MemRegion* R, RVal val) = 0;
|
||||
};
|
||||
|
||||
/// iterBindings - Iterate over the bindings in the Store.
|
||||
virtual void iterBindings(Store store, BindingsHandler& f) = 0;
|
||||
};
|
||||
|
||||
StoreManager* CreateBasicStoreManager(GRStateManager& StMgr);
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
#endif
|
||||
@@ -1,264 +0,0 @@
|
||||
//== SymbolManager.h - Management of 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 defines SymbolManager, a class that manages symbolic values
|
||||
// created for use by GRExprEngine and related classes.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSIS_SYMMGR_H
|
||||
#define LLVM_CLANG_ANALYSIS_SYMMGR_H
|
||||
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
|
||||
class SymbolManager;
|
||||
|
||||
class SymbolID {
|
||||
unsigned Data;
|
||||
public:
|
||||
SymbolID() : Data(~0U - 2) {}
|
||||
SymbolID(unsigned x) : Data(x) {}
|
||||
|
||||
bool isInitialized() const { return Data != (unsigned) (~0U - 2); }
|
||||
operator unsigned() const { return getNumber(); }
|
||||
unsigned getNumber() const { assert (isInitialized()); return Data; }
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID& ID) const {
|
||||
assert (isInitialized());
|
||||
ID.AddInteger(Data);
|
||||
}
|
||||
};
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
namespace llvm {
|
||||
template <> struct DenseMapInfo<clang::SymbolID> {
|
||||
static inline clang::SymbolID getEmptyKey() {
|
||||
return clang::SymbolID(~0U);
|
||||
}
|
||||
static inline clang::SymbolID getTombstoneKey() {
|
||||
return clang::SymbolID(~0U - 1);
|
||||
}
|
||||
static unsigned getHashValue(clang::SymbolID X) {
|
||||
return X.getNumber();
|
||||
}
|
||||
static bool isEqual(clang::SymbolID X, clang::SymbolID Y) {
|
||||
return X.getNumber() == Y.getNumber();
|
||||
}
|
||||
static bool isPod() { return true; }
|
||||
};
|
||||
}
|
||||
|
||||
// SymbolData: Used to record meta data about symbols.
|
||||
|
||||
namespace clang {
|
||||
|
||||
class SymbolData : public llvm::FoldingSetNode {
|
||||
public:
|
||||
enum Kind { UndefKind, ParmKind, GlobalKind, ContentsOfKind, ConjuredKind };
|
||||
|
||||
private:
|
||||
Kind K;
|
||||
SymbolID Sym;
|
||||
|
||||
protected:
|
||||
SymbolData(Kind k, SymbolID sym) : K(k), Sym(sym) {}
|
||||
|
||||
public:
|
||||
virtual ~SymbolData() {}
|
||||
|
||||
Kind getKind() const { return K; }
|
||||
|
||||
SymbolID getSymbol() const { return Sym; }
|
||||
|
||||
QualType getType(const SymbolManager& SymMgr) const;
|
||||
|
||||
virtual void Profile(llvm::FoldingSetNodeID& profile) = 0;
|
||||
|
||||
// Implement isa<T> support.
|
||||
static inline bool classof(const SymbolData*) { return true; }
|
||||
};
|
||||
|
||||
class SymbolDataParmVar : public SymbolData {
|
||||
ParmVarDecl *VD;
|
||||
|
||||
public:
|
||||
SymbolDataParmVar(SymbolID MySym, ParmVarDecl* vd)
|
||||
: SymbolData(ParmKind, MySym), VD(vd) {}
|
||||
|
||||
ParmVarDecl* getDecl() const { return VD; }
|
||||
|
||||
static void Profile(llvm::FoldingSetNodeID& profile, ParmVarDecl* VD) {
|
||||
profile.AddInteger((unsigned) ParmKind);
|
||||
profile.AddPointer(VD);
|
||||
}
|
||||
|
||||
virtual void Profile(llvm::FoldingSetNodeID& profile) {
|
||||
Profile(profile, VD);
|
||||
}
|
||||
|
||||
// Implement isa<T> support.
|
||||
static inline bool classof(const SymbolData* D) {
|
||||
return D->getKind() == ParmKind;
|
||||
}
|
||||
};
|
||||
|
||||
class SymbolDataGlobalVar : public SymbolData {
|
||||
VarDecl *VD;
|
||||
|
||||
public:
|
||||
SymbolDataGlobalVar(SymbolID MySym, VarDecl* vd) :
|
||||
SymbolData(GlobalKind, MySym), VD(vd) {}
|
||||
|
||||
VarDecl* getDecl() const { return VD; }
|
||||
|
||||
static void Profile(llvm::FoldingSetNodeID& profile, VarDecl* VD) {
|
||||
profile.AddInteger((unsigned) GlobalKind);
|
||||
profile.AddPointer(VD);
|
||||
}
|
||||
|
||||
virtual void Profile(llvm::FoldingSetNodeID& profile) {
|
||||
Profile(profile, VD);
|
||||
}
|
||||
|
||||
// Implement isa<T> support.
|
||||
static inline bool classof(const SymbolData* D) {
|
||||
return D->getKind() == GlobalKind;
|
||||
}
|
||||
};
|
||||
|
||||
class SymbolDataContentsOf : public SymbolData {
|
||||
SymbolID Sym;
|
||||
|
||||
public:
|
||||
SymbolDataContentsOf(SymbolID MySym, SymbolID sym) :
|
||||
SymbolData(ContentsOfKind, MySym), Sym(sym) {}
|
||||
|
||||
SymbolID getContainerSymbol() const { return Sym; }
|
||||
|
||||
static void Profile(llvm::FoldingSetNodeID& profile, SymbolID Sym) {
|
||||
profile.AddInteger((unsigned) ContentsOfKind);
|
||||
profile.AddInteger(Sym);
|
||||
}
|
||||
|
||||
virtual void Profile(llvm::FoldingSetNodeID& profile) {
|
||||
Profile(profile, Sym);
|
||||
}
|
||||
|
||||
// Implement isa<T> support.
|
||||
static inline bool classof(const SymbolData* D) {
|
||||
return D->getKind() == ContentsOfKind;
|
||||
}
|
||||
};
|
||||
|
||||
class SymbolConjured : public SymbolData {
|
||||
Expr* E;
|
||||
QualType T;
|
||||
unsigned Count;
|
||||
|
||||
public:
|
||||
SymbolConjured(SymbolID Sym, Expr* exp, QualType t, unsigned count)
|
||||
: SymbolData(ConjuredKind, Sym), E(exp), T(t), Count(count) {}
|
||||
|
||||
Expr* getExpr() const { return E; }
|
||||
unsigned getCount() const { return Count; }
|
||||
|
||||
QualType getType() const { return T; }
|
||||
|
||||
static void Profile(llvm::FoldingSetNodeID& profile,
|
||||
Expr* E, QualType T, unsigned Count) {
|
||||
|
||||
profile.AddInteger((unsigned) ConjuredKind);
|
||||
profile.AddPointer(E);
|
||||
profile.Add(T);
|
||||
profile.AddInteger(Count);
|
||||
}
|
||||
|
||||
virtual void Profile(llvm::FoldingSetNodeID& profile) {
|
||||
Profile(profile, E, T, Count);
|
||||
}
|
||||
|
||||
// Implement isa<T> support.
|
||||
static inline bool classof(const SymbolData* D) {
|
||||
return D->getKind() == ConjuredKind;
|
||||
}
|
||||
};
|
||||
|
||||
// Constraints on symbols. Usually wrapped by RValues.
|
||||
|
||||
class SymIntConstraint : public llvm::FoldingSetNode {
|
||||
SymbolID Symbol;
|
||||
BinaryOperator::Opcode Op;
|
||||
const llvm::APSInt& Val;
|
||||
public:
|
||||
SymIntConstraint(SymbolID sym, BinaryOperator::Opcode op,
|
||||
const llvm::APSInt& V)
|
||||
: Symbol(sym),
|
||||
Op(op), Val(V) {}
|
||||
|
||||
BinaryOperator::Opcode getOpcode() const { return Op; }
|
||||
const SymbolID& getSymbol() const { return Symbol; }
|
||||
const llvm::APSInt& getInt() const { return Val; }
|
||||
|
||||
static inline void Profile(llvm::FoldingSetNodeID& ID,
|
||||
SymbolID Symbol,
|
||||
BinaryOperator::Opcode Op,
|
||||
const llvm::APSInt& Val) {
|
||||
Symbol.Profile(ID);
|
||||
ID.AddInteger(Op);
|
||||
ID.AddPointer(&Val);
|
||||
}
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID& ID) {
|
||||
Profile(ID, Symbol, Op, Val);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class SymbolManager {
|
||||
typedef llvm::FoldingSet<SymbolData> DataSetTy;
|
||||
typedef llvm::DenseMap<SymbolID, SymbolData*> DataMapTy;
|
||||
|
||||
DataSetTy DataSet;
|
||||
DataMapTy DataMap;
|
||||
|
||||
unsigned SymbolCounter;
|
||||
llvm::BumpPtrAllocator& BPAlloc;
|
||||
|
||||
public:
|
||||
SymbolManager(llvm::BumpPtrAllocator& bpalloc)
|
||||
: SymbolCounter(0), BPAlloc(bpalloc) {}
|
||||
|
||||
~SymbolManager();
|
||||
|
||||
SymbolID getSymbol(VarDecl* D);
|
||||
SymbolID getContentsOfSymbol(SymbolID sym);
|
||||
SymbolID getConjuredSymbol(Expr* E, QualType T, unsigned VisitCount);
|
||||
SymbolID getConjuredSymbol(Expr* E, unsigned VisitCount) {
|
||||
return getConjuredSymbol(E, E->getType(), VisitCount);
|
||||
}
|
||||
|
||||
const SymbolData& getSymbolData(SymbolID ID) const;
|
||||
|
||||
QualType getType(SymbolID ID) const {
|
||||
return getSymbolData(ID).getType(*this);
|
||||
}
|
||||
};
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
#endif
|
||||
@@ -1,228 +0,0 @@
|
||||
//==- ProgramPoint.h - Program Points for Path-Sensitive Analysis --*- C++ -*-//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the interface ProgramPoint, which identifies a
|
||||
// distinct location in a function.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSIS_PROGRAM_POINT
|
||||
#define LLVM_CLANG_ANALYSIS_PROGRAM_POINT
|
||||
|
||||
#include "clang/AST/CFG.h"
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
#include <cassert>
|
||||
|
||||
namespace clang {
|
||||
|
||||
class ProgramPoint {
|
||||
public:
|
||||
enum Kind { BlockEdgeKind=0, BlockEntranceKind, BlockExitKind,
|
||||
// Keep the following four together and in this order.
|
||||
PostStmtKind, PostLoadKind, PostStoreKind,
|
||||
PostPurgeDeadSymbolsKind };
|
||||
|
||||
private:
|
||||
std::pair<uintptr_t,uintptr_t> Data;
|
||||
|
||||
protected:
|
||||
ProgramPoint(const void* P, Kind k)
|
||||
: Data(reinterpret_cast<uintptr_t>(P), (uintptr_t) k) {}
|
||||
|
||||
ProgramPoint(const void* P1, const void* P2)
|
||||
: Data(reinterpret_cast<uintptr_t>(P1) | 0x1,
|
||||
reinterpret_cast<uintptr_t>(P2)) {}
|
||||
|
||||
protected:
|
||||
void* getData1NoMask() const {
|
||||
assert (getKind() != BlockEdgeKind);
|
||||
return reinterpret_cast<void*>(Data.first);
|
||||
}
|
||||
|
||||
void* getData1() const {
|
||||
assert (getKind() == BlockEdgeKind);
|
||||
return reinterpret_cast<void*>(Data.first & ~0x1);
|
||||
}
|
||||
|
||||
void* getData2() const {
|
||||
assert (getKind() == BlockEdgeKind);
|
||||
return reinterpret_cast<void*>(Data.second);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
uintptr_t getKind() const {
|
||||
return Data.first & 0x1 ? (uintptr_t) BlockEdgeKind : Data.second;
|
||||
}
|
||||
|
||||
// For use with DenseMap.
|
||||
unsigned getHashValue() const {
|
||||
std::pair<void*,void*> P(reinterpret_cast<void*>(Data.first),
|
||||
reinterpret_cast<void*>(Data.second));
|
||||
return llvm::DenseMapInfo<std::pair<void*,void*> >::getHashValue(P);
|
||||
}
|
||||
|
||||
static bool classof(const ProgramPoint*) { return true; }
|
||||
|
||||
bool operator==(const ProgramPoint & RHS) const {
|
||||
return Data == RHS.Data;
|
||||
}
|
||||
|
||||
bool operator!=(const ProgramPoint& RHS) const {
|
||||
return Data != RHS.Data;
|
||||
}
|
||||
|
||||
bool operator<(const ProgramPoint& RHS) const {
|
||||
return Data < RHS.Data;
|
||||
}
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID& ID) const {
|
||||
ID.AddPointer(reinterpret_cast<void*>(Data.first));
|
||||
ID.AddPointer(reinterpret_cast<void*>(Data.second));
|
||||
}
|
||||
};
|
||||
|
||||
class BlockEntrance : public ProgramPoint {
|
||||
public:
|
||||
BlockEntrance(const CFGBlock* B) : ProgramPoint(B, BlockEntranceKind) {}
|
||||
|
||||
CFGBlock* getBlock() const {
|
||||
return reinterpret_cast<CFGBlock*>(getData1NoMask());
|
||||
}
|
||||
|
||||
Stmt* getFirstStmt() const {
|
||||
CFGBlock* B = getBlock();
|
||||
return B->empty() ? NULL : B->front();
|
||||
}
|
||||
|
||||
static bool classof(const ProgramPoint* Location) {
|
||||
return Location->getKind() == BlockEntranceKind;
|
||||
}
|
||||
};
|
||||
|
||||
class BlockExit : public ProgramPoint {
|
||||
public:
|
||||
BlockExit(const CFGBlock* B) : ProgramPoint(B, BlockExitKind) {}
|
||||
|
||||
CFGBlock* getBlock() const {
|
||||
return reinterpret_cast<CFGBlock*>(getData1NoMask());
|
||||
}
|
||||
|
||||
Stmt* getLastStmt() const {
|
||||
CFGBlock* B = getBlock();
|
||||
return B->empty() ? NULL : B->back();
|
||||
}
|
||||
|
||||
Stmt* getTerminator() const {
|
||||
return getBlock()->getTerminator();
|
||||
}
|
||||
|
||||
static bool classof(const ProgramPoint* Location) {
|
||||
return Location->getKind() == BlockExitKind;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class PostStmt : public ProgramPoint {
|
||||
protected:
|
||||
PostStmt(const Stmt* S, Kind k) : ProgramPoint(S, k) {}
|
||||
public:
|
||||
PostStmt(const Stmt* S) : ProgramPoint(S, PostStmtKind) {}
|
||||
|
||||
Stmt* getStmt() const { return (Stmt*) getData1NoMask(); }
|
||||
|
||||
static bool classof(const ProgramPoint* Location) {
|
||||
unsigned k = Location->getKind();
|
||||
return k >= PostStmtKind && k <= PostPurgeDeadSymbolsKind;
|
||||
}
|
||||
};
|
||||
|
||||
class PostLoad : public PostStmt {
|
||||
public:
|
||||
PostLoad(const Stmt* S) : PostStmt(S, PostLoadKind) {}
|
||||
|
||||
static bool classof(const ProgramPoint* Location) {
|
||||
return Location->getKind() == PostLoadKind;
|
||||
}
|
||||
};
|
||||
|
||||
class PostStore : public PostStmt {
|
||||
public:
|
||||
PostStore(const Stmt* S) : PostStmt(S, PostLoadKind) {}
|
||||
|
||||
static bool classof(const ProgramPoint* Location) {
|
||||
return Location->getKind() == PostStoreKind;
|
||||
}
|
||||
};
|
||||
|
||||
class PostPurgeDeadSymbols : public PostStmt {
|
||||
public:
|
||||
PostPurgeDeadSymbols(const Stmt* S) : PostStmt(S, PostPurgeDeadSymbolsKind) {}
|
||||
|
||||
static bool classof(const ProgramPoint* Location) {
|
||||
return Location->getKind() == PostPurgeDeadSymbolsKind;
|
||||
}
|
||||
};
|
||||
|
||||
class BlockEdge : public ProgramPoint {
|
||||
public:
|
||||
BlockEdge(const CFGBlock* B1, const CFGBlock* B2)
|
||||
: ProgramPoint(B1, B2) {}
|
||||
|
||||
CFGBlock* getSrc() const {
|
||||
return static_cast<CFGBlock*>(getData1());
|
||||
}
|
||||
|
||||
CFGBlock* getDst() const {
|
||||
return static_cast<CFGBlock*>(getData2());
|
||||
}
|
||||
|
||||
static bool classof(const ProgramPoint* Location) {
|
||||
return Location->getKind() == BlockEdgeKind;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
|
||||
namespace llvm { // Traits specialization for DenseMap
|
||||
|
||||
template <> struct DenseMapInfo<clang::ProgramPoint> {
|
||||
|
||||
static inline clang::ProgramPoint getEmptyKey() {
|
||||
uintptr_t x =
|
||||
reinterpret_cast<uintptr_t>(DenseMapInfo<void*>::getEmptyKey()) & ~0x7;
|
||||
return clang::BlockEntrance(reinterpret_cast<clang::CFGBlock*>(x));
|
||||
}
|
||||
|
||||
static inline clang::ProgramPoint getTombstoneKey() {
|
||||
uintptr_t x =
|
||||
reinterpret_cast<uintptr_t>(DenseMapInfo<void*>::getTombstoneKey()) & ~0x7;
|
||||
return clang::BlockEntrance(reinterpret_cast<clang::CFGBlock*>(x));
|
||||
}
|
||||
|
||||
static unsigned getHashValue(const clang::ProgramPoint& Loc) {
|
||||
return Loc.getHashValue();
|
||||
}
|
||||
|
||||
static bool isEqual(const clang::ProgramPoint& L,
|
||||
const clang::ProgramPoint& R) {
|
||||
return L == R;
|
||||
}
|
||||
|
||||
static bool isPod() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
||||
@@ -1,276 +0,0 @@
|
||||
//=- ExprDeclBitVector.h - Dataflow types for Bitvector 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 definition of dataflow types used by analyses such
|
||||
// as LiveVariables and UninitializedValues. The underlying dataflow values
|
||||
// are implemented as bitvectors, but the definitions in this file include
|
||||
// the necessary boilerplate to use with our dataflow framework.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_EXPRDECLBVDVAL_H
|
||||
#define LLVM_CLANG_EXPRDECLBVDVAL_H
|
||||
|
||||
#include "clang/AST/CFG.h"
|
||||
#include "llvm/ADT/BitVector.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
class Expr;
|
||||
class ScopedDecl;
|
||||
|
||||
struct DeclBitVector_Types {
|
||||
|
||||
class Idx {
|
||||
unsigned I;
|
||||
public:
|
||||
explicit Idx(unsigned i) : I(i) {}
|
||||
Idx() : I(~0U) {}
|
||||
|
||||
bool isValid() const {
|
||||
return I != ~0U;
|
||||
}
|
||||
operator unsigned() const {
|
||||
assert (isValid());
|
||||
return I;
|
||||
}
|
||||
};
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// AnalysisDataTy - Whole-function meta data.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
class AnalysisDataTy {
|
||||
public:
|
||||
typedef llvm::DenseMap<const ScopedDecl*, unsigned > DMapTy;
|
||||
typedef DMapTy::const_iterator decl_iterator;
|
||||
|
||||
protected:
|
||||
DMapTy DMap;
|
||||
unsigned NDecls;
|
||||
|
||||
public:
|
||||
|
||||
AnalysisDataTy() : NDecls(0) {}
|
||||
virtual ~AnalysisDataTy() {}
|
||||
|
||||
bool isTracked(const ScopedDecl* SD) { return DMap.find(SD) != DMap.end(); }
|
||||
|
||||
Idx getIdx(const ScopedDecl* SD) const {
|
||||
DMapTy::const_iterator I = DMap.find(SD);
|
||||
return I == DMap.end() ? Idx() : Idx(I->second);
|
||||
}
|
||||
|
||||
unsigned getNumDecls() const { return NDecls; }
|
||||
|
||||
void Register(const ScopedDecl* SD) {
|
||||
if (!isTracked(SD)) DMap[SD] = NDecls++;
|
||||
}
|
||||
|
||||
decl_iterator begin_decl() const { return DMap.begin(); }
|
||||
decl_iterator end_decl() const { return DMap.end(); }
|
||||
};
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// ValTy - Dataflow value.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
class ValTy {
|
||||
llvm::BitVector DeclBV;
|
||||
public:
|
||||
|
||||
void resetValues(AnalysisDataTy& AD) {
|
||||
DeclBV.resize(AD.getNumDecls());
|
||||
DeclBV.reset();
|
||||
}
|
||||
|
||||
bool operator==(const ValTy& RHS) const {
|
||||
assert (sizesEqual(RHS));
|
||||
return DeclBV == RHS.DeclBV;
|
||||
}
|
||||
|
||||
void copyValues(const ValTy& RHS) { DeclBV = RHS.DeclBV; }
|
||||
|
||||
llvm::BitVector::reference getBit(unsigned i) {
|
||||
return DeclBV[i];
|
||||
}
|
||||
|
||||
bool getBit(unsigned i) const {
|
||||
return DeclBV[i];
|
||||
}
|
||||
|
||||
llvm::BitVector::reference
|
||||
operator()(const ScopedDecl* SD, const AnalysisDataTy& AD) {
|
||||
return getBit(AD.getIdx(SD));
|
||||
}
|
||||
|
||||
bool operator()(const ScopedDecl* SD, const AnalysisDataTy& AD) const {
|
||||
return getBit(AD.getIdx(SD));
|
||||
}
|
||||
|
||||
llvm::BitVector::reference getDeclBit(unsigned i) { return DeclBV[i]; }
|
||||
const llvm::BitVector::reference getDeclBit(unsigned i) const {
|
||||
return const_cast<llvm::BitVector&>(DeclBV)[i];
|
||||
}
|
||||
|
||||
ValTy& operator|=(const ValTy& RHS) {
|
||||
assert (sizesEqual(RHS));
|
||||
DeclBV |= RHS.DeclBV;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ValTy& operator&=(const ValTy& RHS) {
|
||||
assert (sizesEqual(RHS));
|
||||
DeclBV &= RHS.DeclBV;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ValTy& OrDeclBits(const ValTy& RHS) {
|
||||
return operator|=(RHS);
|
||||
}
|
||||
|
||||
ValTy& AndDeclBits(const ValTy& RHS) {
|
||||
return operator&=(RHS);
|
||||
}
|
||||
|
||||
bool sizesEqual(const ValTy& RHS) const {
|
||||
return DeclBV.size() == RHS.DeclBV.size();
|
||||
}
|
||||
};
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Some useful merge operations.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
struct Union { void operator()(ValTy& Dst, ValTy& Src) { Dst |= Src; } };
|
||||
struct Intersect { void operator()(ValTy& Dst, ValTy& Src) { Dst &= Src; } };
|
||||
};
|
||||
|
||||
|
||||
struct ExprDeclBitVector_Types {
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// AnalysisDataTy - Whole-function meta data.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
class AnalysisDataTy : public DeclBitVector_Types::AnalysisDataTy {
|
||||
CFG* cfg;
|
||||
public:
|
||||
AnalysisDataTy() {}
|
||||
virtual ~AnalysisDataTy() {}
|
||||
|
||||
void setCFG(CFG* c) { cfg = c; }
|
||||
CFG& getCFG() { assert(cfg && "CFG should not be NULL."); return *cfg; }
|
||||
|
||||
bool isTracked(const Stmt* S) { return cfg->isBlkExpr(S); }
|
||||
using DeclBitVector_Types::AnalysisDataTy::isTracked;
|
||||
|
||||
unsigned getIdx(const Stmt* S) const {
|
||||
CFG::BlkExprNumTy I = cfg->getBlkExprNum(S);
|
||||
assert(I && "expression not tracked for bitvector.");
|
||||
return I;
|
||||
}
|
||||
using DeclBitVector_Types::AnalysisDataTy::getIdx;
|
||||
|
||||
unsigned getNumExprs() const { return cfg->getNumBlkExprs(); }
|
||||
};
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// ValTy - Dataflow value.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
class ValTy : public DeclBitVector_Types::ValTy {
|
||||
llvm::BitVector ExprBV;
|
||||
typedef DeclBitVector_Types::ValTy ParentTy;
|
||||
|
||||
static inline ParentTy& ParentRef(ValTy& X) {
|
||||
return static_cast<ParentTy&>(X);
|
||||
}
|
||||
|
||||
static inline const ParentTy& ParentRef(const ValTy& X) {
|
||||
return static_cast<const ParentTy&>(X);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
void resetValues(AnalysisDataTy& AD) {
|
||||
ParentRef(*this).resetValues(AD);
|
||||
ExprBV.resize(AD.getNumExprs());
|
||||
ExprBV.reset();
|
||||
}
|
||||
|
||||
bool operator==(const ValTy& RHS) const {
|
||||
return ParentRef(*this) == ParentRef(RHS)
|
||||
&& ExprBV == RHS.ExprBV;
|
||||
}
|
||||
|
||||
void copyValues(const ValTy& RHS) {
|
||||
ParentRef(*this).copyValues(ParentRef(RHS));
|
||||
ExprBV = RHS.ExprBV;
|
||||
}
|
||||
|
||||
llvm::BitVector::reference
|
||||
operator()(const Stmt* S, const AnalysisDataTy& AD) {
|
||||
return ExprBV[AD.getIdx(S)];
|
||||
}
|
||||
const llvm::BitVector::reference
|
||||
operator()(const Stmt* S, const AnalysisDataTy& AD) const {
|
||||
return const_cast<ValTy&>(*this)(S,AD);
|
||||
}
|
||||
|
||||
using DeclBitVector_Types::ValTy::operator();
|
||||
|
||||
|
||||
llvm::BitVector::reference getExprBit(unsigned i) { return ExprBV[i]; }
|
||||
const llvm::BitVector::reference getExprBit(unsigned i) const {
|
||||
return const_cast<llvm::BitVector&>(ExprBV)[i];
|
||||
}
|
||||
|
||||
ValTy& OrExprBits(const ValTy& RHS) {
|
||||
ExprBV |= RHS.ExprBV;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ValTy& AndExprBits(const ValTy& RHS) {
|
||||
ExprBV &= RHS.ExprBV;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ValTy& operator|=(const ValTy& RHS) {
|
||||
assert (sizesEqual(RHS));
|
||||
ParentRef(*this) |= ParentRef(RHS);
|
||||
ExprBV |= RHS.ExprBV;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ValTy& operator&=(const ValTy& RHS) {
|
||||
assert (sizesEqual(RHS));
|
||||
ParentRef(*this) &= ParentRef(RHS);
|
||||
ExprBV &= RHS.ExprBV;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool sizesEqual(const ValTy& RHS) const {
|
||||
return ParentRef(*this).sizesEqual(ParentRef(RHS))
|
||||
&& ExprBV.size() == RHS.ExprBV.size();
|
||||
}
|
||||
};
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Some useful merge operations.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
struct Union { void operator()(ValTy& Dst, ValTy& Src) { Dst |= Src; } };
|
||||
struct Intersect { void operator()(ValTy& Dst, ValTy& Src) { Dst &= Src; } };
|
||||
|
||||
};
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
@@ -1,92 +0,0 @@
|
||||
//= CFGRecStmtDeclVisitor - Recursive visitor of CFG stmts/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 implements the template class CFGRecStmtDeclVisitor, which extends
|
||||
// CFGRecStmtVisitor by implementing (typed) visitation of decls.
|
||||
//
|
||||
// FIXME: This may not be fully complete. We currently explore only subtypes
|
||||
// of ScopedDecl.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSIS_CFG_REC_STMT_DECL_VISITOR_H
|
||||
#define LLVM_CLANG_ANALYSIS_CFG_REC_STMT_DECL_VISITOR_H
|
||||
|
||||
#include "clang/Analysis/Visitors/CFGRecStmtVisitor.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/DeclObjC.h"
|
||||
|
||||
#define DISPATCH_CASE(CASE,CLASS) \
|
||||
case Decl::CASE: \
|
||||
static_cast<ImplClass*>(this)->Visit##CLASS(static_cast<CLASS*>(D));\
|
||||
break;
|
||||
|
||||
#define DEFAULT_DISPATCH(CLASS) void Visit##CLASS(CLASS* D) {}
|
||||
#define DEFAULT_DISPATCH_VARDECL(CLASS) void Visit##CLASS(CLASS* D)\
|
||||
{ static_cast<ImplClass*>(this)->VisitVarDecl(D); }
|
||||
|
||||
|
||||
namespace clang {
|
||||
template <typename ImplClass>
|
||||
class CFGRecStmtDeclVisitor : public CFGRecStmtVisitor<ImplClass> {
|
||||
public:
|
||||
|
||||
void VisitDeclRefExpr(DeclRefExpr* DR) {
|
||||
for (ScopedDecl* D = DR->getDecl(); D != NULL; D = D->getNextDeclarator())
|
||||
static_cast<ImplClass*>(this)->VisitScopedDecl(D);
|
||||
}
|
||||
|
||||
void VisitDeclStmt(DeclStmt* DS) {
|
||||
for (DeclStmt::decl_iterator DI = DS->decl_begin(), DE = DS->decl_end();
|
||||
DI != DE; ++DI) {
|
||||
ScopedDecl* D = *DI;
|
||||
static_cast<ImplClass*>(this)->VisitScopedDecl(D);
|
||||
// Visit the initializer.
|
||||
if (VarDecl* VD = dyn_cast<VarDecl>(D))
|
||||
if (Expr* I = VD->getInit())
|
||||
static_cast<ImplClass*>(this)->Visit(I);
|
||||
}
|
||||
}
|
||||
|
||||
void VisitScopedDecl(ScopedDecl* D) {
|
||||
switch (D->getKind()) {
|
||||
DISPATCH_CASE(Function,FunctionDecl)
|
||||
DISPATCH_CASE(Var,VarDecl)
|
||||
DISPATCH_CASE(ParmVar,ParmVarDecl) // FIXME: (same)
|
||||
DISPATCH_CASE(ImplicitParam,ImplicitParamDecl)
|
||||
DISPATCH_CASE(EnumConstant,EnumConstantDecl)
|
||||
DISPATCH_CASE(Typedef,TypedefDecl)
|
||||
DISPATCH_CASE(Struct,RecordDecl) // FIXME: Refine. VisitStructDecl?
|
||||
DISPATCH_CASE(Union,RecordDecl) // FIXME: Refine.
|
||||
DISPATCH_CASE(Class,RecordDecl) // FIXME: Refine.
|
||||
DISPATCH_CASE(Enum,EnumDecl)
|
||||
default:
|
||||
assert(false && "Subtype of ScopedDecl not handled.");
|
||||
}
|
||||
}
|
||||
|
||||
DEFAULT_DISPATCH(VarDecl)
|
||||
DEFAULT_DISPATCH(FunctionDecl)
|
||||
DEFAULT_DISPATCH_VARDECL(ParmVarDecl)
|
||||
DEFAULT_DISPATCH(ImplicitParamDecl)
|
||||
DEFAULT_DISPATCH(EnumConstantDecl)
|
||||
DEFAULT_DISPATCH(TypedefDecl)
|
||||
DEFAULT_DISPATCH(RecordDecl)
|
||||
DEFAULT_DISPATCH(EnumDecl)
|
||||
DEFAULT_DISPATCH(ObjCInterfaceDecl)
|
||||
DEFAULT_DISPATCH(ObjCClassDecl)
|
||||
DEFAULT_DISPATCH(ObjCMethodDecl)
|
||||
DEFAULT_DISPATCH(ObjCProtocolDecl)
|
||||
DEFAULT_DISPATCH(ObjCCategoryDecl)
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#undef DISPATCH_CASE
|
||||
#undef DEFAULT_DISPATCH
|
||||
#endif
|
||||
@@ -1,35 +0,0 @@
|
||||
//==- CFGRecStmtVisitor - Recursive visitor of CFG statements ---*- 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 the template class CFGRecStmtVisitor, which extends
|
||||
// CFGStmtVisitor by implementing a default recursive visit of all statements.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSIS_CFG_REC_STMT_VISITOR_H
|
||||
#define LLVM_CLANG_ANALYSIS_CFG_REC_STMT_VISITOR_H
|
||||
|
||||
#include "clang/Analysis/Visitors/CFGStmtVisitor.h"
|
||||
|
||||
namespace clang {
|
||||
template <typename ImplClass>
|
||||
class CFGRecStmtVisitor : public CFGStmtVisitor<ImplClass,void> {
|
||||
public:
|
||||
|
||||
void VisitStmt(Stmt* S) {
|
||||
static_cast< ImplClass* >(this)->VisitChildren(S);
|
||||
}
|
||||
|
||||
// Defining operator() allows the visitor to be used as a C++ style functor.
|
||||
void operator()(Stmt* S) { static_cast<ImplClass*>(this)->BlockStmt_Visit(S);}
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
@@ -1,151 +0,0 @@
|
||||
//===--- CFGStmtVisitor.h - Visitor for Stmts in a CFG ----------*- 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 CFGStmtVisitor interface, which extends
|
||||
// StmtVisitor. This interface is useful for visiting statements in a CFG
|
||||
// where some statements have implicit control-flow and thus should
|
||||
// be treated specially.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSIS_CFGSTMTVISITOR_H
|
||||
#define LLVM_CLANG_ANALYSIS_CFGSTMTVISITOR_H
|
||||
|
||||
#include "clang/AST/StmtVisitor.h"
|
||||
#include "clang/AST/CFG.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
#define DISPATCH_CASE(CLASS) \
|
||||
case Stmt::CLASS ## Class: return \
|
||||
static_cast<ImplClass*>(this)->BlockStmt_Visit ## CLASS(static_cast<CLASS*>(S));
|
||||
|
||||
#define DEFAULT_BLOCKSTMT_VISIT(CLASS) RetTy BlockStmt_Visit ## CLASS(CLASS *S)\
|
||||
{ return\
|
||||
static_cast<ImplClass*>(this)->BlockStmt_VisitImplicitControlFlowExpr(\
|
||||
cast<Expr>(S)); }
|
||||
|
||||
template <typename ImplClass, typename RetTy=void>
|
||||
class CFGStmtVisitor : public StmtVisitor<ImplClass,RetTy> {
|
||||
Stmt* CurrentBlkStmt;
|
||||
|
||||
struct NullifyStmt {
|
||||
Stmt*& S;
|
||||
|
||||
NullifyStmt(Stmt*& s) : S(s) {}
|
||||
~NullifyStmt() { S = NULL; }
|
||||
};
|
||||
|
||||
public:
|
||||
CFGStmtVisitor() : CurrentBlkStmt(NULL) {}
|
||||
|
||||
Stmt* getCurrentBlkStmt() const { return CurrentBlkStmt; }
|
||||
|
||||
RetTy Visit(Stmt* S) {
|
||||
if (S == CurrentBlkStmt ||
|
||||
!static_cast<ImplClass*>(this)->getCFG().isBlkExpr(S))
|
||||
return StmtVisitor<ImplClass,RetTy>::Visit(S);
|
||||
else
|
||||
return RetTy();
|
||||
}
|
||||
|
||||
/// BlockVisit_XXX - Visitor methods for visiting the "root" statements in
|
||||
/// CFGBlocks. Root statements are the statements that appear explicitly in
|
||||
/// the list of statements in a CFGBlock. For substatements, or when there
|
||||
/// is no implementation provided for a BlockStmt_XXX method, we default
|
||||
/// to using StmtVisitor's Visit method.
|
||||
RetTy BlockStmt_Visit(Stmt* S) {
|
||||
CurrentBlkStmt = S;
|
||||
NullifyStmt cleanup(CurrentBlkStmt);
|
||||
|
||||
switch (S->getStmtClass()) {
|
||||
|
||||
DISPATCH_CASE(StmtExpr)
|
||||
DISPATCH_CASE(ConditionalOperator)
|
||||
|
||||
case Stmt::BinaryOperatorClass: {
|
||||
BinaryOperator* B = cast<BinaryOperator>(S);
|
||||
if (B->isLogicalOp())
|
||||
return static_cast<ImplClass*>(this)->BlockStmt_VisitLogicalOp(B);
|
||||
else if (B->getOpcode() == BinaryOperator::Comma)
|
||||
return static_cast<ImplClass*>(this)->BlockStmt_VisitComma(B);
|
||||
// Fall through.
|
||||
}
|
||||
|
||||
default:
|
||||
if (isa<Expr>(S))
|
||||
return
|
||||
static_cast<ImplClass*>(this)->BlockStmt_VisitExpr(cast<Expr>(S));
|
||||
else
|
||||
return static_cast<ImplClass*>(this)->BlockStmt_VisitStmt(S);
|
||||
}
|
||||
}
|
||||
|
||||
DEFAULT_BLOCKSTMT_VISIT(StmtExpr)
|
||||
DEFAULT_BLOCKSTMT_VISIT(ConditionalOperator)
|
||||
|
||||
RetTy BlockStmt_VisitImplicitControlFlowExpr(Expr* E) {
|
||||
return static_cast<ImplClass*>(this)->BlockStmt_VisitExpr(E);
|
||||
}
|
||||
|
||||
RetTy BlockStmt_VisitExpr(Expr* E) {
|
||||
return static_cast<ImplClass*>(this)->BlockStmt_VisitStmt(E);
|
||||
}
|
||||
|
||||
RetTy BlockStmt_VisitStmt(Stmt* S) {
|
||||
return static_cast<ImplClass*>(this)->Visit(S);
|
||||
}
|
||||
|
||||
RetTy BlockStmt_VisitLogicalOp(BinaryOperator* B) {
|
||||
return
|
||||
static_cast<ImplClass*>(this)->BlockStmt_VisitImplicitControlFlowExpr(B);
|
||||
}
|
||||
|
||||
RetTy BlockStmt_VisitComma(BinaryOperator* B) {
|
||||
return
|
||||
static_cast<ImplClass*>(this)->BlockStmt_VisitImplicitControlFlowExpr(B);
|
||||
}
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Utility methods. Not called by default (but subclasses may use them).
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
/// VisitChildren: Call "Visit" on each child of S.
|
||||
void VisitChildren(Stmt* S) {
|
||||
|
||||
switch (S->getStmtClass()) {
|
||||
default:
|
||||
break;
|
||||
|
||||
case Stmt::StmtExprClass: {
|
||||
CompoundStmt* CS = cast<StmtExpr>(S)->getSubStmt();
|
||||
if (CS->body_empty()) return;
|
||||
static_cast<ImplClass*>(this)->Visit(CS->body_back());
|
||||
return;
|
||||
}
|
||||
|
||||
case Stmt::BinaryOperatorClass: {
|
||||
BinaryOperator* B = cast<BinaryOperator>(S);
|
||||
if (B->getOpcode() != BinaryOperator::Comma) break;
|
||||
static_cast<ImplClass*>(this)->Visit(B->getRHS());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (Stmt::child_iterator I=S->child_begin(), E=S->child_end(); I != E;++I)
|
||||
if (*I) static_cast<ImplClass*>(this)->Visit(*I);
|
||||
}
|
||||
};
|
||||
|
||||
#undef DEFAULT_BLOCKSTMT_VISIT
|
||||
#undef DISPATCH_CASE
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
@@ -1,64 +0,0 @@
|
||||
//==- CFGVarDeclVisitor - Generic visitor of VarDecls in a CFG --*- 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 the template class CFGVarDeclVisitor, which provides
|
||||
// a generic way to visit all the VarDecl's in a CFG.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSIS_CFG_VARDECL_VISITOR_H
|
||||
#define LLVM_CLANG_ANALYSIS_CFG_VARDECL_VISITOR_H
|
||||
|
||||
#include "clang/Analysis/Visitors/CFGStmtVisitor.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/Stmt.h"
|
||||
#include "clang/AST/CFG.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
template <typename ImplClass>
|
||||
class CFGVarDeclVisitor : public CFGStmtVisitor<ImplClass> {
|
||||
const CFG& cfg;
|
||||
public:
|
||||
CFGVarDeclVisitor(const CFG& c) : cfg(c) {}
|
||||
|
||||
void VisitStmt(Stmt* S) {
|
||||
static_cast<ImplClass*>(this)->VisitChildren(S);
|
||||
}
|
||||
|
||||
void VisitDeclRefExpr(DeclRefExpr* DR) {
|
||||
static_cast<ImplClass*>(this)->VisitDeclChain(DR->getDecl());
|
||||
}
|
||||
|
||||
void VisitDeclStmt(DeclStmt* DS) {
|
||||
static_cast<ImplClass*>(this)->VisitDeclChain(DS->getDecl());
|
||||
}
|
||||
|
||||
void VisitDeclChain(ScopedDecl* D) {
|
||||
for (; D != NULL ; D = D->getNextDeclarator())
|
||||
static_cast<ImplClass*>(this)->VisitScopedDecl(D);
|
||||
}
|
||||
|
||||
void VisitScopedDecl(ScopedDecl* D) {
|
||||
if (VarDecl* V = dyn_cast<VarDecl>(D))
|
||||
static_cast<ImplClass*>(this)->VisitVarDecl(V);
|
||||
}
|
||||
|
||||
void VisitVarDecl(VarDecl* D) {}
|
||||
|
||||
void VisitAllDecls() {
|
||||
for (CFG::const_iterator BI = cfg.begin(), BE = cfg.end(); BI != BE; ++BI)
|
||||
for (CFGBlock::const_iterator SI=BI->begin(),SE = BI->end();SI != SE;++SI)
|
||||
static_cast<ImplClass*>(this)->BlockStmt_Visit(const_cast<Stmt*>(*SI));
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
@@ -1,213 +0,0 @@
|
||||
//===--- Diagnostic.h - C Language Family 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 Diagnostic-related interfaces.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_DIAGNOSTIC_H
|
||||
#define LLVM_CLANG_DIAGNOSTIC_H
|
||||
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
|
||||
namespace clang {
|
||||
class DiagnosticClient;
|
||||
class SourceRange;
|
||||
class SourceManager;
|
||||
|
||||
// Import the diagnostic enums themselves.
|
||||
namespace diag {
|
||||
class CustomDiagInfo;
|
||||
|
||||
/// diag::kind - All of the diagnostics that can be emitted by the frontend.
|
||||
enum kind {
|
||||
#define DIAG(ENUM,FLAGS,DESC) ENUM,
|
||||
#include "DiagnosticKinds.def"
|
||||
NUM_BUILTIN_DIAGNOSTICS
|
||||
};
|
||||
|
||||
/// Enum values that allow the client to map NOTEs, WARNINGs, and EXTENSIONs
|
||||
/// to either MAP_IGNORE (nothing), MAP_WARNING (emit a warning), MAP_ERROR
|
||||
/// (emit as an error), or MAP_DEFAULT (handle the default way).
|
||||
enum Mapping {
|
||||
MAP_DEFAULT = 0, //< Do not map this diagnostic.
|
||||
MAP_IGNORE = 1, //< Map this diagnostic to nothing, ignore it.
|
||||
MAP_WARNING = 2, //< Map this diagnostic to a warning.
|
||||
MAP_ERROR = 3 //< Map this diagnostic to an error.
|
||||
};
|
||||
}
|
||||
|
||||
/// Diagnostic - This concrete class is used by the front-end to report
|
||||
/// problems and issues. It massages the diagnostics (e.g. handling things like
|
||||
/// "report warnings as errors" and passes them off to the DiagnosticClient for
|
||||
/// reporting to the user.
|
||||
class Diagnostic {
|
||||
public:
|
||||
/// Level - The level of the diagnostic, after it has been through mapping.
|
||||
enum Level {
|
||||
Ignored, Note, Warning, Error, Fatal
|
||||
};
|
||||
|
||||
private:
|
||||
bool IgnoreAllWarnings; // Ignore all warnings: -w
|
||||
bool WarningsAsErrors; // Treat warnings like errors:
|
||||
bool WarnOnExtensions; // Enables warnings for gcc extensions: -pedantic.
|
||||
bool ErrorOnExtensions; // Error on extensions: -pedantic-errors.
|
||||
bool SuppressSystemWarnings;// Suppress warnings in system headers.
|
||||
DiagnosticClient *Client;
|
||||
|
||||
/// DiagMappings - Mapping information for diagnostics. Mapping info is
|
||||
/// packed into two bits per diagnostic.
|
||||
unsigned char DiagMappings[(diag::NUM_BUILTIN_DIAGNOSTICS+3)/4];
|
||||
|
||||
/// ErrorOccurred - This is set to true when an error is emitted, and is
|
||||
/// sticky.
|
||||
bool ErrorOccurred;
|
||||
|
||||
unsigned NumDiagnostics; // Number of diagnostics reported
|
||||
unsigned NumErrors; // Number of diagnostics that are errors
|
||||
|
||||
/// CustomDiagInfo - Information for uniquing and looking up custom diags.
|
||||
diag::CustomDiagInfo *CustomDiagInfo;
|
||||
|
||||
public:
|
||||
explicit Diagnostic(DiagnosticClient *client = 0);
|
||||
~Diagnostic();
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Diagnostic characterization methods, used by a client to customize how
|
||||
//
|
||||
|
||||
DiagnosticClient *getClient() { return Client; };
|
||||
const DiagnosticClient *getClient() const { return Client; };
|
||||
|
||||
void setClient(DiagnosticClient* client) { Client = client; }
|
||||
|
||||
/// setIgnoreAllWarnings - When set to true, any unmapped warnings are
|
||||
/// ignored. If this and WarningsAsErrors are both set, then this one wins.
|
||||
void setIgnoreAllWarnings(bool Val) { IgnoreAllWarnings = Val; }
|
||||
bool getIgnoreAllWarnings() const { return IgnoreAllWarnings; }
|
||||
|
||||
/// setWarningsAsErrors - When set to true, any warnings reported are issued
|
||||
/// as errors.
|
||||
void setWarningsAsErrors(bool Val) { WarningsAsErrors = Val; }
|
||||
bool getWarningsAsErrors() const { return WarningsAsErrors; }
|
||||
|
||||
/// setWarnOnExtensions - When set to true, issue warnings on GCC extensions,
|
||||
/// the equivalent of GCC's -pedantic.
|
||||
void setWarnOnExtensions(bool Val) { WarnOnExtensions = Val; }
|
||||
bool getWarnOnExtensions() const { return WarnOnExtensions; }
|
||||
|
||||
/// setErrorOnExtensions - When set to true issue errors for GCC extensions
|
||||
/// instead of warnings. This is the equivalent to GCC's -pedantic-errors.
|
||||
void setErrorOnExtensions(bool Val) { ErrorOnExtensions = Val; }
|
||||
bool getErrorOnExtensions() const { return ErrorOnExtensions; }
|
||||
|
||||
/// setSuppressSystemWarnings - When set to true mask warnings that
|
||||
/// come from system headers.
|
||||
void setSuppressSystemWarnings(bool Val) { SuppressSystemWarnings = Val; }
|
||||
bool getSuppressSystemWarnings() const { return SuppressSystemWarnings; }
|
||||
|
||||
/// setDiagnosticMapping - This allows the client to specify that certain
|
||||
/// warnings are ignored. Only NOTEs, WARNINGs, and EXTENSIONs can be mapped.
|
||||
void setDiagnosticMapping(diag::kind Diag, diag::Mapping Map) {
|
||||
assert(Diag < diag::NUM_BUILTIN_DIAGNOSTICS &&
|
||||
"Can only map builtin diagnostics");
|
||||
assert(isBuiltinNoteWarningOrExtension(Diag) && "Cannot map errors!");
|
||||
unsigned char &Slot = DiagMappings[Diag/4];
|
||||
unsigned Bits = (Diag & 3)*2;
|
||||
Slot &= ~(3 << Bits);
|
||||
Slot |= Map << Bits;
|
||||
}
|
||||
|
||||
/// getDiagnosticMapping - Return the mapping currently set for the specified
|
||||
/// diagnostic.
|
||||
diag::Mapping getDiagnosticMapping(diag::kind Diag) const {
|
||||
return (diag::Mapping)((DiagMappings[Diag/4] >> (Diag & 3)*2) & 3);
|
||||
}
|
||||
|
||||
bool hasErrorOccurred() const { return ErrorOccurred; }
|
||||
|
||||
unsigned getNumErrors() const { return NumErrors; }
|
||||
unsigned getNumDiagnostics() const { return NumDiagnostics; }
|
||||
|
||||
/// getCustomDiagID - Return an ID for a diagnostic with the specified message
|
||||
/// and level. If this is the first request for this diagnosic, it is
|
||||
/// registered and created, otherwise the existing ID is returned.
|
||||
unsigned getCustomDiagID(Level L, const char *Message);
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Diagnostic classification and reporting interfaces.
|
||||
//
|
||||
|
||||
/// getDescription - Given a diagnostic ID, return a description of the
|
||||
/// issue.
|
||||
const char *getDescription(unsigned DiagID);
|
||||
|
||||
/// isBuiltinNoteWarningOrExtension - Return true if the unmapped diagnostic
|
||||
/// level of the specified diagnostic ID is a Note, Warning, or Extension.
|
||||
/// Note that this only works on builtin diagnostics, not custom ones.
|
||||
static bool isBuiltinNoteWarningOrExtension(unsigned DiagID);
|
||||
|
||||
/// getDiagnosticLevel - Based on the way the client configured the Diagnostic
|
||||
/// object, classify the specified diagnostic ID into a Level, consumable by
|
||||
/// the DiagnosticClient.
|
||||
Level getDiagnosticLevel(unsigned DiagID) const;
|
||||
|
||||
/// Report - Issue the message to the client. DiagID is a member of the
|
||||
/// diag::kind enum.
|
||||
void Report(FullSourceLoc Pos, unsigned DiagID,
|
||||
const std::string *Strs = 0, unsigned NumStrs = 0,
|
||||
const SourceRange *Ranges = 0, unsigned NumRanges = 0) {
|
||||
Report(NULL, Pos, DiagID, Strs, NumStrs, Ranges, NumRanges);
|
||||
}
|
||||
|
||||
/// Report - Issue the message to the client. DiagID is a member of the
|
||||
/// diag::kind enum.
|
||||
void Report(unsigned DiagID,
|
||||
const std::string *Strs = 0, unsigned NumStrs = 0,
|
||||
const SourceRange *Ranges = 0, unsigned NumRanges = 0) {
|
||||
Report(FullSourceLoc(), DiagID, Strs, NumStrs, Ranges, NumRanges);
|
||||
}
|
||||
|
||||
/// Report - Issue the message to the specified client.
|
||||
/// DiagID is a member of the diag::kind enum.
|
||||
void Report(DiagnosticClient* C, FullSourceLoc Pos, unsigned DiagID,
|
||||
const std::string *Strs = 0, unsigned NumStrs = 0,
|
||||
const SourceRange *Ranges = 0, unsigned NumRanges = 0);
|
||||
};
|
||||
|
||||
/// DiagnosticClient - This is an abstract interface implemented by clients of
|
||||
/// the front-end, which formats and prints fully processed diagnostics.
|
||||
class DiagnosticClient {
|
||||
protected:
|
||||
std::string FormatDiagnostic(Diagnostic &Diags, Diagnostic::Level Level,
|
||||
diag::kind ID,
|
||||
const std::string *Strs,
|
||||
unsigned NumStrs);
|
||||
public:
|
||||
virtual ~DiagnosticClient();
|
||||
|
||||
/// HandleDiagnostic - Handle this diagnostic, reporting it to the user or
|
||||
/// capturing it to a log as needed.
|
||||
virtual void HandleDiagnostic(Diagnostic &Diags,
|
||||
Diagnostic::Level DiagLevel,
|
||||
FullSourceLoc Pos,
|
||||
diag::kind ID,
|
||||
const std::string *Strs,
|
||||
unsigned NumStrs,
|
||||
const SourceRange *Ranges,
|
||||
unsigned NumRanges) = 0;
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,125 +0,0 @@
|
||||
//===--- FileManager.h - File System Probing and Caching --------*- 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 FileManager interface.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_FILEMANAGER_H
|
||||
#define LLVM_CLANG_FILEMANAGER_H
|
||||
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/Bitcode/SerializationFwd.h"
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <string>
|
||||
// FIXME: Enhance libsystem to support inode and other fields in stat.
|
||||
#include <sys/types.h>
|
||||
|
||||
namespace clang {
|
||||
class FileManager;
|
||||
|
||||
/// DirectoryEntry - Cached information about one directory on the disk.
|
||||
///
|
||||
class DirectoryEntry {
|
||||
const char *Name; // Name of the directory.
|
||||
friend class FileManager;
|
||||
public:
|
||||
DirectoryEntry() : Name(0) {}
|
||||
const char *getName() const { return Name; }
|
||||
};
|
||||
|
||||
/// FileEntry - Cached information about one file on the disk.
|
||||
///
|
||||
class FileEntry {
|
||||
const char *Name; // Name of the file.
|
||||
off_t Size; // File size in bytes.
|
||||
time_t ModTime; // Modification time of file.
|
||||
const DirectoryEntry *Dir; // Directory file lives in.
|
||||
unsigned UID; // A unique (small) ID for the file.
|
||||
dev_t Device; // ID for the device containing the file.
|
||||
ino_t Inode; // Inode number for the file.
|
||||
friend class FileManager;
|
||||
public:
|
||||
FileEntry(dev_t device, ino_t inode) : Name(0), Device(device), Inode(inode){}
|
||||
// Add a default constructor for use with llvm::StringMap
|
||||
FileEntry() : Name(0), Device(0), Inode(0) {}
|
||||
|
||||
const char *getName() const { return Name; }
|
||||
off_t getSize() const { return Size; }
|
||||
unsigned getUID() const { return UID; }
|
||||
ino_t getInode() const { return Inode; }
|
||||
dev_t getDevice() const { return Device; }
|
||||
time_t getModificationTime() const { return ModTime; }
|
||||
|
||||
/// getDir - Return the directory the file lives in.
|
||||
///
|
||||
const DirectoryEntry *getDir() const { return Dir; }
|
||||
|
||||
bool operator<(const FileEntry& RHS) const {
|
||||
return Device < RHS.Device || (Device == RHS.Device && Inode < RHS.Inode);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/// FileManager - Implements support for file system lookup, file system
|
||||
/// caching, and directory search management. This also handles more advanced
|
||||
/// properties, such as uniquing files based on "inode", so that a file with two
|
||||
/// names (e.g. symlinked) will be treated as a single file.
|
||||
///
|
||||
class FileManager {
|
||||
|
||||
class UniqueDirContainer;
|
||||
class UniqueFileContainer;
|
||||
|
||||
/// UniqueDirs/UniqueFiles - Cache for existing directories/files.
|
||||
///
|
||||
UniqueDirContainer &UniqueDirs;
|
||||
UniqueFileContainer &UniqueFiles;
|
||||
|
||||
/// DirEntries/FileEntries - This is a cache of directory/file entries we have
|
||||
/// looked up. The actual Entry is owned by UniqueFiles/UniqueDirs above.
|
||||
///
|
||||
llvm::StringMap<DirectoryEntry*> DirEntries;
|
||||
llvm::StringMap<FileEntry*> FileEntries;
|
||||
|
||||
/// NextFileUID - Each FileEntry we create is assigned a unique ID #.
|
||||
///
|
||||
unsigned NextFileUID;
|
||||
|
||||
// Statistics.
|
||||
unsigned NumDirLookups, NumFileLookups;
|
||||
unsigned NumDirCacheMisses, NumFileCacheMisses;
|
||||
public:
|
||||
FileManager();
|
||||
~FileManager();
|
||||
|
||||
/// getDirectory - Lookup, cache, and verify the specified directory. This
|
||||
/// returns null if the directory doesn't exist.
|
||||
///
|
||||
const DirectoryEntry *getDirectory(const std::string &Filename) {
|
||||
return getDirectory(&Filename[0], &Filename[0] + Filename.size());
|
||||
}
|
||||
const DirectoryEntry *getDirectory(const char *FileStart,const char *FileEnd);
|
||||
|
||||
/// getFile - Lookup, cache, and verify the specified file. This returns null
|
||||
/// if the file doesn't exist.
|
||||
///
|
||||
const FileEntry *getFile(const std::string &Filename) {
|
||||
return getFile(&Filename[0], &Filename[0] + Filename.size());
|
||||
}
|
||||
const FileEntry *getFile(const char *FilenameStart,
|
||||
const char *FilenameEnd);
|
||||
|
||||
void PrintStats() const;
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user