Compare commits
26 Commits
llvmorg-5.
...
llvmorg-2.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
379f6c725a | ||
|
|
12fcf50efc | ||
|
|
7972a0a2a7 | ||
|
|
9b8ff0bf0d | ||
|
|
3a9c75b2c7 | ||
|
|
b7956f6e91 | ||
|
|
9b3a8a3642 | ||
|
|
a4f46144d8 | ||
|
|
a9cb83a33c | ||
|
|
4f5f70ed22 | ||
|
|
8924ecceb6 | ||
|
|
6db25e01e9 | ||
|
|
e541679475 | ||
|
|
7d0b6f0493 | ||
|
|
d7231a6922 | ||
|
|
3e28c35890 | ||
|
|
9c108f4e20 | ||
|
|
422c8d1184 | ||
|
|
c1e0cbf19d | ||
|
|
f8d3031906 | ||
|
|
72857109a4 | ||
|
|
30c8db9aa9 | ||
|
|
4231f713b9 | ||
|
|
1621e89545 | ||
|
|
797cb5ba60 | ||
|
|
468bddb269 |
@@ -1,990 +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 "HTMLDiagnostics.h"
|
||||
#include "clang/AST/TranslationUnit.h"
|
||||
#include "clang/Analysis/PathDiagnostic.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "clang/Basic/FileManager.h"
|
||||
#include "clang/AST/AST.h"
|
||||
#include "clang/AST/ASTConsumer.h"
|
||||
#include "clang/AST/CFG.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/Timer.h"
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
|
||||
using namespace clang;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// DeclPrinter - Utility class for printing top-level decls.
|
||||
|
||||
namespace {
|
||||
class DeclPrinter {
|
||||
public:
|
||||
std::ostream& Out;
|
||||
|
||||
DeclPrinter(std::ostream* out) : Out(out ? *out : *llvm::cerr.stream()) {}
|
||||
DeclPrinter() : Out(*llvm::cerr.stream()) {}
|
||||
|
||||
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
|
||||
|
||||
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 (isa<ObjCClassDecl>(D)) {
|
||||
Out << "@class [printing todo]\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() << ") ";
|
||||
// FIXME: just print original selector name!
|
||||
Out << OMD->getSelector().getName();
|
||||
|
||||
for (unsigned i = 0, e = OMD->getNumParams(); i != e; ++i) {
|
||||
ParmVarDecl *PDecl = OMD->getParamDecl(i);
|
||||
// FIXME: selector is missing here!
|
||||
Out << " :(" << PDecl->getType().getAsString() << ") " << PDecl->getName();
|
||||
}
|
||||
}
|
||||
|
||||
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?
|
||||
int count = OID->getNumIntfRefProtocols();
|
||||
|
||||
if (count > 0) {
|
||||
ObjCProtocolDecl **refProtocols = OID->getReferencedProtocols();
|
||||
for (int i = 0; i < count; i++)
|
||||
Out << (i == 0 ? '<' : ',') << refProtocols[i]->getName();
|
||||
}
|
||||
|
||||
if (count > 0)
|
||||
Out << ">\n";
|
||||
else
|
||||
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::OBJC_PR_IMPL_SYNTHSIZE)
|
||||
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(std::ostream* o = NULL) : DeclPrinter(o) {}
|
||||
|
||||
virtual void HandleTopLevelDecl(Decl *D) {
|
||||
PrintDecl(D);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
ASTConsumer *clang::CreateASTPrinter(std::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";
|
||||
} else if (isa<ObjCImplementationDecl>(D)) {
|
||||
Out << "Read objc 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(); }
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// CFGVisitor & VisitCFGs - Boilerplate interface and logic to visit
|
||||
// the CFGs for all function definitions.
|
||||
|
||||
namespace {
|
||||
|
||||
class CFGVisitor : public ASTConsumer {
|
||||
std::string FName;
|
||||
public:
|
||||
CFGVisitor(const std::string& fname) : FName(fname) {}
|
||||
CFGVisitor() : FName("") {}
|
||||
|
||||
// CFG Visitor interface to be implemented by subclass.
|
||||
virtual void VisitCFG(CFG& C, Decl& CD) = 0;
|
||||
virtual bool printFuncDeclStart() { return true; }
|
||||
|
||||
virtual void HandleTopLevelDecl(Decl *D);
|
||||
};
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
void CFGVisitor::HandleTopLevelDecl(Decl *D) {
|
||||
|
||||
CFG *C = NULL;
|
||||
|
||||
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
|
||||
|
||||
if (!FD->getBody())
|
||||
return;
|
||||
|
||||
if (FName.size() > 0 && FName != FD->getIdentifier()->getName())
|
||||
return;
|
||||
|
||||
if (printFuncDeclStart()) {
|
||||
DeclPrinter().PrintFunctionDeclStart(FD);
|
||||
llvm::cerr << '\n';
|
||||
}
|
||||
|
||||
C = CFG::buildCFG(FD->getBody());
|
||||
}
|
||||
else if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
|
||||
|
||||
if (!MD->getBody())
|
||||
return;
|
||||
|
||||
if (FName.size() > 0 && FName != MD->getSelector().getName())
|
||||
return;
|
||||
|
||||
if (printFuncDeclStart()) {
|
||||
DeclPrinter().PrintObjCMethodDecl(MD);
|
||||
llvm::cerr << '\n';
|
||||
}
|
||||
|
||||
C = CFG::buildCFG(MD->getBody());
|
||||
}
|
||||
|
||||
if (C) {
|
||||
VisitCFG(*C, *D);
|
||||
delete C;
|
||||
}
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// DumpCFGs - Dump CFGs to stderr or visualize with Graphviz
|
||||
|
||||
namespace {
|
||||
class CFGDumper : public CFGVisitor {
|
||||
const bool UseGraphviz;
|
||||
public:
|
||||
CFGDumper(bool use_graphviz, const std::string& fname)
|
||||
: CFGVisitor(fname), UseGraphviz(use_graphviz) {}
|
||||
|
||||
virtual void VisitCFG(CFG& C, Decl&) {
|
||||
if (UseGraphviz)
|
||||
C.viewCFG();
|
||||
else
|
||||
C.dump();
|
||||
}
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
ASTConsumer *clang::CreateCFGDumper(bool ViewGraphs, const std::string& FName) {
|
||||
return new CFGDumper(ViewGraphs, FName);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// AnalyzeLiveVariables - perform live variable analysis and dump results
|
||||
|
||||
namespace {
|
||||
class LivenessVisitor : public CFGVisitor {
|
||||
SourceManager *SM;
|
||||
public:
|
||||
LivenessVisitor(const std::string& fname) : CFGVisitor(fname) {}
|
||||
|
||||
virtual void Initialize(ASTContext &Context) {
|
||||
SM = &Context.getSourceManager();
|
||||
}
|
||||
|
||||
virtual void VisitCFG(CFG& C, Decl& CD) {
|
||||
LiveVariables L(C);
|
||||
L.runOnCFG(C);
|
||||
L.dumpBlockLiveness(*SM);
|
||||
}
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
ASTConsumer *clang::CreateLiveVarAnalyzer(const std::string& fname) {
|
||||
return new LivenessVisitor(fname);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// DeadStores - run checker to locate dead stores in a function
|
||||
|
||||
namespace {
|
||||
class DeadStoreVisitor : public CFGVisitor {
|
||||
Diagnostic &Diags;
|
||||
ASTContext *Ctx;
|
||||
public:
|
||||
DeadStoreVisitor(Diagnostic &diags) : Diags(diags) {}
|
||||
virtual void Initialize(ASTContext &Context) {
|
||||
Ctx = &Context;
|
||||
}
|
||||
|
||||
virtual void VisitCFG(CFG& C, Decl& CD) {
|
||||
CheckDeadStores(C, *Ctx, Diags);
|
||||
}
|
||||
|
||||
virtual bool printFuncDeclStart() { return false; }
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
ASTConsumer *clang::CreateDeadStoreChecker(Diagnostic &Diags) {
|
||||
return new DeadStoreVisitor(Diags);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Unitialized Values - run checker to flag potential uses of uninitalized
|
||||
// variables.
|
||||
|
||||
namespace {
|
||||
class UninitValsVisitor : public CFGVisitor {
|
||||
Diagnostic &Diags;
|
||||
ASTContext *Ctx;
|
||||
public:
|
||||
UninitValsVisitor(Diagnostic &diags) : Diags(diags) {}
|
||||
virtual void Initialize(ASTContext &Context) {
|
||||
Ctx = &Context;
|
||||
}
|
||||
|
||||
virtual void VisitCFG(CFG& C, Decl&) {
|
||||
CheckUninitializedValues(C, *Ctx, Diags);
|
||||
}
|
||||
|
||||
virtual bool printFuncDeclStart() { return false; }
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
ASTConsumer *clang::CreateUnitValsChecker(Diagnostic &Diags) {
|
||||
return new UninitValsVisitor(Diags);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// CheckerConsumer - Generic Driver for running intra-procedural path-sensitive
|
||||
// analyses.
|
||||
|
||||
namespace {
|
||||
|
||||
class CheckerConsumer : public CFGVisitor {
|
||||
protected:
|
||||
Diagnostic &Diags;
|
||||
ASTContext* Ctx;
|
||||
Preprocessor* PP;
|
||||
PreprocessorFactory* PPF;
|
||||
const std::string& HTMLDir;
|
||||
bool Visualize;
|
||||
bool TrimGraph;
|
||||
llvm::OwningPtr<PathDiagnosticClient> PD;
|
||||
bool AnalyzeAll;
|
||||
public:
|
||||
CheckerConsumer(Diagnostic &diags, Preprocessor* pp, PreprocessorFactory* ppf,
|
||||
const std::string& fname,
|
||||
const std::string& htmldir,
|
||||
bool visualize, bool trim, bool analyzeAll)
|
||||
: CFGVisitor(fname), Diags(diags), PP(pp), PPF(ppf), HTMLDir(htmldir),
|
||||
Visualize(visualize), TrimGraph(trim), AnalyzeAll(analyzeAll) {}
|
||||
|
||||
virtual void Initialize(ASTContext &Context) { Ctx = &Context; }
|
||||
virtual void VisitCFG(CFG& C, Decl&);
|
||||
virtual bool printFuncDeclStart() { return false; }
|
||||
|
||||
virtual const char* getCheckerName() = 0;
|
||||
virtual void getTransferFunctions(std::vector<GRTransferFuncs*>& TFs) = 0;
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
void CheckerConsumer::VisitCFG(CFG& C, Decl& CD) {
|
||||
|
||||
if (Diags.hasErrorOccurred())
|
||||
return;
|
||||
|
||||
SourceLocation Loc = CD.getLocation();
|
||||
|
||||
if (!Loc.isFileID())
|
||||
return;
|
||||
|
||||
if (!AnalyzeAll && !Ctx->getSourceManager().isFromMainFile(Loc))
|
||||
return;
|
||||
|
||||
// Lazily create the diagnostic client.
|
||||
|
||||
if (!HTMLDir.empty() && PD.get() == NULL)
|
||||
PD.reset(CreateHTMLDiagnosticClient(HTMLDir, PP, PPF));
|
||||
|
||||
|
||||
if (!Visualize) {
|
||||
|
||||
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(&CD)) {
|
||||
llvm::cerr << "ANALYZE: "
|
||||
<< Ctx->getSourceManager().getSourceName(FD->getLocation())
|
||||
<< ' '
|
||||
<< FD->getIdentifier()->getName()
|
||||
<< '\n';
|
||||
}
|
||||
else if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(&CD)) {
|
||||
llvm::cerr << "ANALYZE (ObjC Method): "
|
||||
<< Ctx->getSourceManager().getSourceName(MD->getLocation())
|
||||
<< " '"
|
||||
<< MD->getSelector().getName() << "'\n";
|
||||
}
|
||||
}
|
||||
else
|
||||
llvm::cerr << '\n';
|
||||
|
||||
std::vector<GRTransferFuncs*> TFs;
|
||||
getTransferFunctions(TFs);
|
||||
|
||||
while (!TFs.empty()) {
|
||||
|
||||
// Construct the analysis engine.
|
||||
GRExprEngine Eng(C, CD, *Ctx);
|
||||
|
||||
// Set base transfer functions.
|
||||
llvm::OwningPtr<GRTransferFuncs> TF(TFs.back());
|
||||
TFs.pop_back();
|
||||
|
||||
Eng.setTransferFunctions(TF.get());
|
||||
|
||||
// Execute the worklist algorithm.
|
||||
Eng.ExecuteWorkList();
|
||||
|
||||
// Display warnings.
|
||||
Eng.EmitWarnings(Diags, PD.get());
|
||||
|
||||
#ifndef NDEBUG
|
||||
if (Visualize) Eng.ViewGraph(TrimGraph);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// GRSimpleVals - Perform intra-procedural, path-sensitive constant propagation.
|
||||
|
||||
namespace {
|
||||
class GRSimpleValsVisitor : public CheckerConsumer {
|
||||
public:
|
||||
GRSimpleValsVisitor(Diagnostic &diags, Preprocessor* pp,
|
||||
PreprocessorFactory* ppf,
|
||||
const std::string& fname, const std::string& htmldir,
|
||||
bool visualize, bool trim, bool analyzeAll)
|
||||
: CheckerConsumer(diags, pp, ppf, fname, htmldir, visualize,
|
||||
trim, analyzeAll) {}
|
||||
|
||||
virtual const char* getCheckerName() { return "GRSimpleVals"; }
|
||||
|
||||
virtual void getTransferFunctions(std::vector<GRTransferFuncs*>& TFs) {
|
||||
return TFs.push_back(MakeGRSimpleValsTF());
|
||||
}
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
ASTConsumer* clang::CreateGRSimpleVals(Diagnostic &Diags,
|
||||
Preprocessor* PP,
|
||||
PreprocessorFactory* PPF,
|
||||
const std::string& FunctionName,
|
||||
const std::string& HTMLDir,
|
||||
bool Visualize, bool TrimGraph,
|
||||
bool AnalyzeAll) {
|
||||
|
||||
return new GRSimpleValsVisitor(Diags, PP, PPF, FunctionName, HTMLDir,
|
||||
Visualize, TrimGraph, AnalyzeAll);
|
||||
}
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Core Foundation Reference Counting Checker
|
||||
|
||||
namespace {
|
||||
class CFRefCountCheckerVisitor : public CheckerConsumer {
|
||||
const LangOptions& LangOpts;
|
||||
public:
|
||||
CFRefCountCheckerVisitor(Diagnostic &diags, Preprocessor* pp,
|
||||
PreprocessorFactory* ppf,
|
||||
const LangOptions& lopts,
|
||||
const std::string& fname,
|
||||
const std::string& htmldir,
|
||||
bool visualize, bool trim, bool analyzeAll)
|
||||
: CheckerConsumer(diags, pp, ppf, fname, htmldir, visualize,
|
||||
trim, analyzeAll), LangOpts(lopts) {}
|
||||
|
||||
virtual const char* getCheckerName() { return "CFRefCountChecker"; }
|
||||
|
||||
virtual void getTransferFunctions(std::vector<GRTransferFuncs*>& TFs) {
|
||||
switch (LangOpts.getGCMode()) {
|
||||
case LangOptions::NonGC:
|
||||
TFs.push_back(MakeCFRefCountTF(*Ctx, false, true, LangOpts));
|
||||
break;
|
||||
|
||||
case LangOptions::GCOnly:
|
||||
TFs.push_back(MakeCFRefCountTF(*Ctx, true, true, LangOpts));
|
||||
break;
|
||||
|
||||
case LangOptions::HybridGC:
|
||||
TFs.push_back(MakeCFRefCountTF(*Ctx, false, true, LangOpts));
|
||||
TFs.push_back(MakeCFRefCountTF(*Ctx, true, false, LangOpts));
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
ASTConsumer* clang::CreateCFRefChecker(Diagnostic &Diags,
|
||||
Preprocessor* PP,
|
||||
PreprocessorFactory* PPF,
|
||||
const LangOptions& LangOpts,
|
||||
const std::string& FunctionName,
|
||||
const std::string& HTMLDir,
|
||||
bool Visualize, bool TrimGraph,
|
||||
bool AnalyzeAll) {
|
||||
|
||||
return new CFRefCountCheckerVisitor(Diags, PP, PPF, LangOpts, FunctionName,
|
||||
HTMLDir, Visualize, TrimGraph,
|
||||
AnalyzeAll);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// AST Serializer
|
||||
|
||||
namespace {
|
||||
|
||||
class ASTSerializer : public ASTConsumer {
|
||||
protected:
|
||||
Diagnostic &Diags;
|
||||
const LangOptions& lang;
|
||||
TranslationUnit* TU;
|
||||
|
||||
public:
|
||||
ASTSerializer(Diagnostic& diags, const LangOptions& LO)
|
||||
: Diags(diags), lang(LO), TU(0) {}
|
||||
|
||||
virtual ~ASTSerializer() { delete TU; }
|
||||
|
||||
virtual void Initialize(ASTContext &Context) {
|
||||
if (!TU) TU = new TranslationUnit(Context, lang);
|
||||
}
|
||||
|
||||
virtual void HandleTopLevelDecl(Decl *D) {
|
||||
if (Diags.hasErrorOccurred())
|
||||
return;
|
||||
|
||||
if (TU) TU->AddTopLevelDecl(D);
|
||||
}
|
||||
};
|
||||
|
||||
class SingleFileSerializer : public ASTSerializer {
|
||||
const llvm::sys::Path FName;
|
||||
public:
|
||||
SingleFileSerializer(const llvm::sys::Path& F, Diagnostic &diags,
|
||||
const LangOptions &LO)
|
||||
: ASTSerializer(diags,LO), FName(F) {}
|
||||
|
||||
~SingleFileSerializer() {
|
||||
EmitASTBitcodeFile(TU, FName);
|
||||
}
|
||||
};
|
||||
|
||||
class BuildSerializer : public ASTSerializer {
|
||||
llvm::sys::Path EmitDir;
|
||||
public:
|
||||
BuildSerializer(const llvm::sys::Path& dir, Diagnostic &diags,
|
||||
const LangOptions &LO)
|
||||
: ASTSerializer(diags,LO), EmitDir(dir) {}
|
||||
|
||||
~BuildSerializer() {
|
||||
|
||||
if (!TU)
|
||||
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,
|
||||
const LangOptions &Features) {
|
||||
|
||||
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, Features);
|
||||
}
|
||||
|
||||
// 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, Features);
|
||||
}
|
||||
@@ -1,80 +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 <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(std::ostream* OS = NULL);
|
||||
|
||||
ASTConsumer *CreateASTDumper();
|
||||
|
||||
ASTConsumer *CreateASTViewer();
|
||||
|
||||
ASTConsumer *CreateCFGDumper(bool ViewGraphs, const std::string& FName);
|
||||
|
||||
ASTConsumer *CreateLiveVarAnalyzer(const std::string& fname);
|
||||
|
||||
ASTConsumer *CreateDeadStoreChecker(Diagnostic &Diags);
|
||||
|
||||
ASTConsumer *CreateUnitValsChecker(Diagnostic &Diags);
|
||||
|
||||
ASTConsumer *CreateGRSimpleVals(Diagnostic &Diags,
|
||||
Preprocessor* PP, PreprocessorFactory* PPF,
|
||||
const std::string& Function,
|
||||
const std::string& HTMLDir, bool Visualize,
|
||||
bool TrimGraph, bool AnalyzeAll);
|
||||
|
||||
ASTConsumer *CreateCFRefChecker(Diagnostic &Diags,
|
||||
Preprocessor* PP, PreprocessorFactory* PPF,
|
||||
const LangOptions& LangOpts,
|
||||
const std::string& Function,
|
||||
const std::string& HTMLDir, bool Visualize,
|
||||
bool TrimGraph, bool AnalyzeAll);
|
||||
|
||||
ASTConsumer *CreateCodeRewriterTest(const std::string& InFile,
|
||||
const std::string& OutFile,
|
||||
Diagnostic &Diags,
|
||||
const LangOptions &LOpts);
|
||||
|
||||
ASTConsumer* CreateHTMLPrinter(const std::string &OutFile, Diagnostic &D,
|
||||
Preprocessor *PP, PreprocessorFactory* PPF);
|
||||
|
||||
ASTConsumer *CreateSerializationTest(Diagnostic &Diags,
|
||||
FileManager& FMgr,
|
||||
const LangOptions &LOpts);
|
||||
|
||||
ASTConsumer *CreateASTSerializer(const std::string& InFile,
|
||||
const std::string& EmitDir,
|
||||
Diagnostic &Diags,
|
||||
const LangOptions &LOpts);
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
#endif
|
||||
@@ -1,239 +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 "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";
|
||||
|
||||
/// 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) {
|
||||
// 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);
|
||||
}
|
||||
} 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 TextDiagnosticBuffer &Diags =
|
||||
static_cast<const TextDiagnosticBuffer&>(PP.getDiagnostics().getClient());
|
||||
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:");
|
||||
|
||||
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);
|
||||
|
||||
// Gather the set of expected diagnostics.
|
||||
DiagList ExpectedErrors, ExpectedWarnings;
|
||||
FindExpectedDiags(PP, ExpectedErrors, ExpectedWarnings);
|
||||
|
||||
// Check that the expected diagnostics occurred.
|
||||
return CheckResults(PP, ExpectedErrors, ExpectedWarnings);
|
||||
}
|
||||
@@ -1,399 +0,0 @@
|
||||
//===--- HTMLDiagnostics.cpp - HTML Diagnostics for Paths ----*- 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 HTMLDiagnostics object.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "HTMLDiagnostics.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "clang/Basic/FileManager.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/Analysis/PathDiagnostic.h"
|
||||
#include "clang/Rewrite/Rewriter.h"
|
||||
#include "clang/Rewrite/HTMLRewrite.h"
|
||||
#include "clang/Lex/Lexer.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/Support/Streams.h"
|
||||
#include "llvm/System/Path.h"
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
using namespace clang;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Boilerplate.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace {
|
||||
|
||||
class VISIBILITY_HIDDEN HTMLDiagnostics : public PathDiagnosticClient {
|
||||
llvm::sys::Path Directory, FilePrefix;
|
||||
bool createdDir, noDir;
|
||||
Preprocessor* PP;
|
||||
PreprocessorFactory* PPF;
|
||||
std::vector<const PathDiagnostic*> BatchedDiags;
|
||||
public:
|
||||
HTMLDiagnostics(const std::string& prefix, Preprocessor* pp,
|
||||
PreprocessorFactory* ppf);
|
||||
|
||||
virtual ~HTMLDiagnostics();
|
||||
|
||||
virtual void HandlePathDiagnostic(const PathDiagnostic* D);
|
||||
|
||||
void HandlePiece(Rewriter& R, const PathDiagnosticPiece& P,
|
||||
unsigned num, unsigned max);
|
||||
|
||||
void HighlightRange(Rewriter& R, SourceRange Range);
|
||||
|
||||
void ReportDiag(const PathDiagnostic& D);
|
||||
};
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
HTMLDiagnostics::HTMLDiagnostics(const std::string& prefix, Preprocessor* pp,
|
||||
PreprocessorFactory* ppf)
|
||||
: Directory(prefix), FilePrefix(prefix), createdDir(false), noDir(false),
|
||||
PP(pp), PPF(ppf) {
|
||||
|
||||
// All html files begin with "report"
|
||||
FilePrefix.appendComponent("report");
|
||||
}
|
||||
|
||||
PathDiagnosticClient*
|
||||
clang::CreateHTMLDiagnosticClient(const std::string& prefix, Preprocessor* PP,
|
||||
PreprocessorFactory* PPF) {
|
||||
|
||||
return new HTMLDiagnostics(prefix, PP, PPF);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Report processing.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void HTMLDiagnostics::HandlePathDiagnostic(const PathDiagnostic* D) {
|
||||
if (!D)
|
||||
return;
|
||||
|
||||
if (D->empty()) {
|
||||
delete D;
|
||||
return;
|
||||
}
|
||||
|
||||
BatchedDiags.push_back(D);
|
||||
}
|
||||
|
||||
HTMLDiagnostics::~HTMLDiagnostics() {
|
||||
|
||||
while (!BatchedDiags.empty()) {
|
||||
const PathDiagnostic* D = BatchedDiags.back();
|
||||
BatchedDiags.pop_back();
|
||||
ReportDiag(*D);
|
||||
delete D;
|
||||
}
|
||||
}
|
||||
|
||||
void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D) {
|
||||
|
||||
// Create the HTML directory if it is missing.
|
||||
|
||||
if (!createdDir) {
|
||||
createdDir = true;
|
||||
std::string ErrorMsg;
|
||||
Directory.createDirectoryOnDisk(true, &ErrorMsg);
|
||||
|
||||
if (!Directory.isDirectory()) {
|
||||
llvm::cerr << "warning: could not create directory '"
|
||||
<< Directory.toString() << "'\n"
|
||||
<< "reason: " << ErrorMsg << '\n';
|
||||
|
||||
noDir = true;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (noDir)
|
||||
return;
|
||||
|
||||
// Create a new rewriter to generate HTML.
|
||||
SourceManager& SMgr = D.begin()->getLocation().getManager();
|
||||
Rewriter R(SMgr);
|
||||
|
||||
// Process the path.
|
||||
|
||||
unsigned n = D.size();
|
||||
unsigned max = n;
|
||||
|
||||
for (PathDiagnostic::const_reverse_iterator I=D.rbegin(), E=D.rend();
|
||||
I!=E; ++I, --n) {
|
||||
|
||||
HandlePiece(R, *I, n, max);
|
||||
}
|
||||
|
||||
// Add line numbers, header, footer, etc.
|
||||
|
||||
unsigned FileID = R.getSourceMgr().getMainFileID();
|
||||
html::EscapeText(R, FileID);
|
||||
html::AddLineNumbers(R, FileID);
|
||||
|
||||
// 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);
|
||||
|
||||
// FIXME: We eventually want to use PPF to create a fresh Preprocessor,
|
||||
// once we have worked out the bugs.
|
||||
//
|
||||
// if (PPF) html::HighlightMacros(R, FileID, *PPF);
|
||||
//
|
||||
if (PP) html::HighlightMacros(R, FileID, *PP);
|
||||
|
||||
// Get the full directory name of the analyzed file.
|
||||
|
||||
const FileEntry* Entry = SMgr.getFileEntryForID(FileID);
|
||||
|
||||
// This is a cludge; basically we want to append either the full
|
||||
// working directory if we have no directory information. This is
|
||||
// a work in progress.
|
||||
|
||||
std::string DirName = "";
|
||||
|
||||
if (!llvm::sys::Path(Entry->getName()).isAbsolute()) {
|
||||
llvm::sys::Path P = llvm::sys::Path::GetCurrentDirectory();
|
||||
DirName = P.toString() + "/";
|
||||
}
|
||||
|
||||
// Add the name of the file as an <h1> tag.
|
||||
|
||||
{
|
||||
std::ostringstream os;
|
||||
|
||||
os << "<h3>Bug Summary</h3>\n<table class=\"simpletable\">\n"
|
||||
"<tr><td class=\"rowname\">File:</td><td>"
|
||||
<< html::EscapeText(DirName)
|
||||
<< html::EscapeText(Entry->getName())
|
||||
<< "</td></tr>\n<tr><td class=\"rowname\">Location:</td><td>"
|
||||
"<a href=\"#EndPath\">line "
|
||||
<< (*D.rbegin()).getLocation().getLogicalLineNumber()
|
||||
<< ", column "
|
||||
<< (*D.rbegin()).getLocation().getLogicalColumnNumber()
|
||||
<< "</a></td></tr>\n"
|
||||
"<tr><td class=\"rowname\">Description:</td><td>"
|
||||
<< D.getDescription() << "</td></tr>\n";
|
||||
|
||||
// Output any other meta data.
|
||||
|
||||
for (PathDiagnostic::meta_iterator I=D.meta_begin(), E=D.meta_end();
|
||||
I!=E; ++I) {
|
||||
os << "<tr><td></td><td>" << html::EscapeText(*I) << "</td></tr>\n";
|
||||
}
|
||||
|
||||
os << "</table>\n<h3>Annotated Source Code</h3>\n";
|
||||
|
||||
R.InsertStrBefore(SourceLocation::getFileLoc(FileID, 0), os.str());
|
||||
}
|
||||
|
||||
// Embed meta-data tags.
|
||||
|
||||
const std::string& BugDesc = D.getDescription();
|
||||
|
||||
if (!BugDesc.empty()) {
|
||||
std::ostringstream os;
|
||||
os << "\n<!-- BUGDESC " << BugDesc << " -->\n";
|
||||
R.InsertStrBefore(SourceLocation::getFileLoc(FileID, 0), os.str());
|
||||
}
|
||||
|
||||
{
|
||||
std::ostringstream os;
|
||||
os << "\n<!-- BUGFILE " << DirName << Entry->getName() << " -->\n";
|
||||
R.InsertStrBefore(SourceLocation::getFileLoc(FileID, 0), os.str());
|
||||
}
|
||||
|
||||
{
|
||||
std::ostringstream os;
|
||||
os << "\n<!-- BUGLINE " << D.back()->getLocation().getLogicalLineNumber()
|
||||
<< " -->\n";
|
||||
R.InsertStrBefore(SourceLocation::getFileLoc(FileID, 0), os.str());
|
||||
}
|
||||
|
||||
{
|
||||
std::ostringstream os;
|
||||
os << "\n<!-- BUGPATHLENGTH " << D.size() << " -->\n";
|
||||
R.InsertStrBefore(SourceLocation::getFileLoc(FileID, 0), os.str());
|
||||
}
|
||||
|
||||
// Add CSS, header, and footer.
|
||||
|
||||
html::AddHeaderFooterInternalBuiltinCSS(R, FileID);
|
||||
|
||||
// Get the rewrite buffer.
|
||||
const RewriteBuffer *Buf = R.getRewriteBufferFor(FileID);
|
||||
|
||||
if (!Buf) {
|
||||
llvm::cerr << "warning: no diagnostics generated for main file.\n";
|
||||
return;
|
||||
}
|
||||
|
||||
// Create the stream to write out the HTML.
|
||||
std::ofstream os;
|
||||
|
||||
{
|
||||
// Create a path for the target HTML file.
|
||||
llvm::sys::Path F(FilePrefix);
|
||||
F.makeUnique(false, NULL);
|
||||
|
||||
// Rename the file with an HTML extension.
|
||||
llvm::sys::Path H(F);
|
||||
H.appendSuffix("html");
|
||||
F.renamePathOnDisk(H, NULL);
|
||||
|
||||
os.open(H.toString().c_str());
|
||||
|
||||
if (!os) {
|
||||
llvm::cerr << "warning: could not create file '" << F.toString() << "'\n";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Emit the HTML to disk.
|
||||
|
||||
for (RewriteBuffer::iterator I = Buf->begin(), E = Buf->end(); I!=E; ++I)
|
||||
os << *I;
|
||||
}
|
||||
|
||||
void HTMLDiagnostics::HandlePiece(Rewriter& R,
|
||||
const PathDiagnosticPiece& P,
|
||||
unsigned num, unsigned max) {
|
||||
|
||||
// For now, just draw a box above the line in question, and emit the
|
||||
// warning.
|
||||
|
||||
FullSourceLoc Pos = P.getLocation();
|
||||
|
||||
if (!Pos.isValid())
|
||||
return;
|
||||
|
||||
SourceManager& SM = R.getSourceMgr();
|
||||
FullSourceLoc LPos = Pos.getLogicalLoc();
|
||||
unsigned FileID = SM.getCanonicalFileID(LPos.getLocation());
|
||||
|
||||
assert (&LPos.getManager() == &SM && "SourceManagers are different!");
|
||||
|
||||
if (!SM.isFromMainFile(LPos.getLocation()))
|
||||
return;
|
||||
|
||||
const llvm::MemoryBuffer *Buf = SM.getBuffer(FileID);
|
||||
const char* FileStart = Buf->getBufferStart();
|
||||
|
||||
|
||||
// Compute the column number. Rewind from the current position to the start
|
||||
// of the line.
|
||||
|
||||
unsigned ColNo = LPos.getColumnNumber();
|
||||
const char *TokLogicalPtr = LPos.getCharacterData();
|
||||
const char *LineStart = TokLogicalPtr-ColNo;
|
||||
|
||||
// Only compute LineEnd if we display below a line.
|
||||
const char *LineEnd = TokLogicalPtr;
|
||||
|
||||
if (P.getDisplayHint() == PathDiagnosticPiece::Below) {
|
||||
const char* FileEnd = Buf->getBufferEnd();
|
||||
|
||||
while (*LineEnd != '\n' && LineEnd != FileEnd)
|
||||
++LineEnd;
|
||||
}
|
||||
|
||||
// Compute the margin offset by counting tabs and non-tabs.
|
||||
|
||||
unsigned PosNo = 0;
|
||||
|
||||
for (const char* c = LineStart; c != TokLogicalPtr; ++c)
|
||||
PosNo += *c == '\t' ? 8 : 1;
|
||||
|
||||
// Create the html for the message.
|
||||
|
||||
std::ostringstream os;
|
||||
|
||||
os << "\n<tr><td class=\"num\"></td><td class=\"line\">"
|
||||
<< "<div id=\"";
|
||||
|
||||
if (num == max)
|
||||
os << "EndPath";
|
||||
else
|
||||
os << "Path" << num;
|
||||
|
||||
os << "\" class=\"msg\" style=\"margin-left:"
|
||||
<< PosNo << "ex\">";
|
||||
|
||||
if (max > 1)
|
||||
os << "<span class=\"PathIndex\">[" << num << "]</span> ";
|
||||
|
||||
os << html::EscapeText(P.getString()) << "</div></td></tr>";
|
||||
|
||||
// Insert the new html.
|
||||
|
||||
unsigned DisplayPos = 0;
|
||||
|
||||
switch (P.getDisplayHint()) {
|
||||
case PathDiagnosticPiece::Above:
|
||||
DisplayPos = LineStart - FileStart;
|
||||
break;
|
||||
case PathDiagnosticPiece::Below:
|
||||
DisplayPos = LineEnd - FileStart;
|
||||
break;
|
||||
default:
|
||||
assert (false && "Unhandled hint.");
|
||||
}
|
||||
|
||||
R.InsertStrBefore(SourceLocation::getFileLoc(FileID, DisplayPos), os.str());
|
||||
|
||||
// Now highlight the ranges.
|
||||
|
||||
for (const SourceRange *I = P.ranges_begin(), *E = P.ranges_end();
|
||||
I != E; ++I)
|
||||
HighlightRange(R, *I);
|
||||
}
|
||||
|
||||
void HTMLDiagnostics::HighlightRange(Rewriter& R, SourceRange Range) {
|
||||
|
||||
SourceManager& SM = R.getSourceMgr();
|
||||
|
||||
SourceLocation LogicalStart = SM.getLogicalLoc(Range.getBegin());
|
||||
unsigned StartLineNo = SM.getLineNumber(LogicalStart);
|
||||
|
||||
SourceLocation LogicalEnd = SM.getLogicalLoc(Range.getEnd());
|
||||
unsigned EndLineNo = SM.getLineNumber(LogicalEnd);
|
||||
|
||||
if (EndLineNo < StartLineNo)
|
||||
return;
|
||||
|
||||
if (!SM.isFromMainFile(LogicalStart) ||
|
||||
!SM.isFromMainFile(LogicalEnd))
|
||||
return;
|
||||
|
||||
// Compute the column number of the end.
|
||||
unsigned EndColNo = SM.getColumnNumber(LogicalEnd);
|
||||
unsigned OldEndColNo = EndColNo;
|
||||
|
||||
if (EndColNo) {
|
||||
// Add in the length of the token, so that we cover multi-char tokens.
|
||||
EndColNo += Lexer::MeasureTokenLength(Range.getEnd(), SM) - 1;
|
||||
}
|
||||
|
||||
// Highlight the range. Make the span tag the outermost tag for the
|
||||
// selected range.
|
||||
|
||||
SourceLocation E = LogicalEnd.getFileLocWithOffset(EndColNo - OldEndColNo);
|
||||
|
||||
html::HighlightRange(R, LogicalStart, E,
|
||||
"<span class=\"mrange\">", "</span>");
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
//===--- HTMLPathDiagnostic.h - HTML Diagnostics for Paths ------*- 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 create a HTMLPathDiagnostic object.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_PATH_HTML_DIAGNOSTIC_H
|
||||
#define LLVM_CLANG_PATH_HTML_DIAGNOSTIC_H
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace clang {
|
||||
|
||||
class PathDiagnosticClient;
|
||||
class Preprocessor;
|
||||
class PreprocessorFactory;
|
||||
|
||||
|
||||
PathDiagnosticClient* CreateHTMLDiagnosticClient(const std::string& prefix,
|
||||
Preprocessor* PP,
|
||||
PreprocessorFactory* PPF);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,93 +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/Rewrite/Rewriter.h"
|
||||
#include "clang/Rewrite/HTMLRewrite.h"
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
#include "clang/Basic/SourceManager.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();
|
||||
html::AddLineNumbers(R, FileID);
|
||||
html::AddHeaderFooterInternalBuiltinCSS(R, FileID);
|
||||
|
||||
// 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,13 +0,0 @@
|
||||
LEVEL = ../../..
|
||||
CPPFLAGS += -I$(PROJ_SRC_DIR)/../include
|
||||
CXXFLAGS = -fno-rtti
|
||||
|
||||
TOOLNAME = clang
|
||||
USEDLIBS = clangCodeGen.a clangAnalysis.a clangRewrite.a clangSEMA.a \
|
||||
clangAST.a clangParse.a clangLex.a clangBasic.a \
|
||||
LLVMCore.a LLVMSupport.a LLVMSystem.a \
|
||||
LLVMBitWriter.a LLVMBitReader.a LLVMCodeGen.a LLVMTarget.a
|
||||
|
||||
|
||||
|
||||
include $(LEVEL)/Makefile.common
|
||||
@@ -1,57 +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) {}
|
||||
|
||||
/// 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 << "ActOnDeclarator ";
|
||||
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 << "ActOnPopScope\n";
|
||||
|
||||
// Pass up to EmptyActions so that the symbol table is maintained right.
|
||||
MinimalAction::ActOnPopScope(Loc, S);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
MinimalAction *clang::CreatePrintParserActionsAction(IdentifierTable &IT) {
|
||||
return new ParserPrintActions(IT);
|
||||
}
|
||||
@@ -1,685 +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 <cstdio>
|
||||
using namespace clang;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Simple buffered I/O
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Empirically, iostream is over 30% slower than stdio for this workload, and
|
||||
// stdio itself isn't very well suited. The problem with stdio is use of
|
||||
// putchar_unlocked. We have many newline characters that need to be emitted,
|
||||
// but stdio needs to do extra checks to handle line buffering mode. These
|
||||
// extra checks make putchar_unlocked fall off its inlined code path, hitting
|
||||
// slow system code. In practice, using 'write' directly makes 'clang -E -P'
|
||||
// about 10% faster than using the stdio path on darwin.
|
||||
|
||||
#if defined(HAVE_UNISTD_H) && defined(HAVE_FCNTL_H)
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#else
|
||||
#define USE_STDIO 1
|
||||
#endif
|
||||
|
||||
static std::string OutputFilename;
|
||||
#ifdef USE_STDIO
|
||||
static FILE *OutputFILE;
|
||||
#else
|
||||
static int OutputFD;
|
||||
static char *OutBufStart = 0, *OutBufEnd, *OutBufCur;
|
||||
#endif
|
||||
|
||||
/// InitOutputBuffer - Initialize our output buffer.
|
||||
///
|
||||
static void InitOutputBuffer(const std::string& Output) {
|
||||
#ifdef USE_STDIO
|
||||
if (!Output.size() || Output == "-")
|
||||
OutputFILE = stdout;
|
||||
else {
|
||||
OutputFilename = Output;
|
||||
OutputFILE = fopen(Output.c_str(), "w+");
|
||||
|
||||
if (OutputFILE == 0) {
|
||||
fprintf(stderr, "Error opening output file '%s'.\n", Output.c_str());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
assert(OutputFILE && "failed to open output file");
|
||||
#else
|
||||
OutBufStart = new char[64*1024];
|
||||
OutBufEnd = OutBufStart+64*1024;
|
||||
OutBufCur = OutBufStart;
|
||||
|
||||
if (!Output.size() || Output == "-")
|
||||
OutputFD = STDOUT_FILENO;
|
||||
else {
|
||||
OutputFilename = Output;
|
||||
OutputFD = open(Output.c_str(), O_WRONLY|O_CREAT|O_TRUNC, 0644);
|
||||
if (OutputFD < 0) {
|
||||
fprintf(stderr, "Error opening output file '%s'.\n", Output.c_str());
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef USE_STDIO
|
||||
/// FlushBuffer - Write the accumulated bytes to the output stream.
|
||||
///
|
||||
static void FlushBuffer() {
|
||||
write(OutputFD, OutBufStart, OutBufCur-OutBufStart);
|
||||
OutBufCur = OutBufStart;
|
||||
}
|
||||
#endif
|
||||
|
||||
/// CleanupOutputBuffer - Finish up output.
|
||||
///
|
||||
static void CleanupOutputBuffer(bool ErrorOccurred) {
|
||||
#ifdef USE_STDIO
|
||||
if (OutputFILE != stdout)
|
||||
fclose(OutputFILE);
|
||||
#else
|
||||
FlushBuffer();
|
||||
delete [] OutBufStart;
|
||||
if (OutputFD != STDOUT_FILENO)
|
||||
close(OutputFD);
|
||||
#endif
|
||||
|
||||
// If an error occurred, remove the output file.
|
||||
if (ErrorOccurred && !OutputFilename.empty())
|
||||
llvm::sys::Path(OutputFilename).eraseFromDisk();
|
||||
}
|
||||
|
||||
static void OutputChar(char c) {
|
||||
#if defined(_MSC_VER)
|
||||
putc(c, OutputFILE);
|
||||
#elif defined(USE_STDIO)
|
||||
putc_unlocked(c, OutputFILE);
|
||||
#else
|
||||
if (OutBufCur >= OutBufEnd)
|
||||
FlushBuffer();
|
||||
*OutBufCur++ = c;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void OutputString(const char *Ptr, unsigned Size) {
|
||||
#ifdef USE_STDIO
|
||||
fwrite(Ptr, Size, 1, OutputFILE);
|
||||
#else
|
||||
if (OutBufCur+Size >= OutBufEnd)
|
||||
FlushBuffer();
|
||||
|
||||
switch (Size) {
|
||||
default:
|
||||
memcpy(OutBufCur, Ptr, Size);
|
||||
break;
|
||||
case 3:
|
||||
OutBufCur[2] = Ptr[2];
|
||||
case 2:
|
||||
OutBufCur[1] = Ptr[1];
|
||||
case 1:
|
||||
OutBufCur[0] = Ptr[0];
|
||||
case 0:
|
||||
break;
|
||||
}
|
||||
OutBufCur += Size;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// 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;
|
||||
unsigned CurLine;
|
||||
bool EmittedTokensOnThisLine;
|
||||
DirectoryLookup::DirType FileType;
|
||||
llvm::SmallString<512> CurFilename;
|
||||
public:
|
||||
PrintPPOutputPPCallbacks(Preprocessor &pp) : PP(pp) {
|
||||
CurLine = 0;
|
||||
CurFilename += "<uninit>";
|
||||
EmittedTokensOnThisLine = false;
|
||||
FileType = DirectoryLookup::NormalHeaderDir;
|
||||
}
|
||||
|
||||
void SetEmittedTokensOnThisLine() { EmittedTokensOnThisLine = true; }
|
||||
bool hasEmittedTokensOnThisLine() const { return EmittedTokensOnThisLine; }
|
||||
|
||||
virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason,
|
||||
DirectoryLookup::DirType 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);
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
/// UToStr - Do itoa on the specified number, in-place in the specified buffer.
|
||||
/// endptr points to the end of the buffer.
|
||||
static char *UToStr(unsigned N, char *EndPtr) {
|
||||
// Null terminate the buffer.
|
||||
*--EndPtr = '\0';
|
||||
if (N == 0) // Zero is a special case.
|
||||
*--EndPtr = '0';
|
||||
while (N) {
|
||||
*--EndPtr = '0' + char(N % 10);
|
||||
N /= 10;
|
||||
}
|
||||
return EndPtr;
|
||||
}
|
||||
|
||||
|
||||
/// 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) {
|
||||
if (DisableLineMarkers) {
|
||||
unsigned LineNo = PP.getSourceManager().getLogicalLineNumber(Loc);
|
||||
if (LineNo == CurLine) return false;
|
||||
|
||||
CurLine = LineNo;
|
||||
|
||||
if (!EmittedTokensOnThisLine)
|
||||
return true;
|
||||
|
||||
OutputChar('\n');
|
||||
EmittedTokensOnThisLine = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned LineNo = PP.getSourceManager().getLogicalLineNumber(Loc);
|
||||
|
||||
// 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)
|
||||
OutputChar('\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";
|
||||
OutputString(NewLines, LineNo-CurLine);
|
||||
}
|
||||
CurLine = LineNo;
|
||||
} else {
|
||||
if (EmittedTokensOnThisLine) {
|
||||
OutputChar('\n');
|
||||
EmittedTokensOnThisLine = false;
|
||||
}
|
||||
|
||||
CurLine = LineNo;
|
||||
|
||||
OutputChar('#');
|
||||
OutputChar(' ');
|
||||
char NumberBuffer[20];
|
||||
const char *NumStr = UToStr(LineNo, NumberBuffer+20);
|
||||
OutputString(NumStr, (NumberBuffer+20)-NumStr-1);
|
||||
OutputChar(' ');
|
||||
OutputChar('"');
|
||||
OutputString(&CurFilename[0], CurFilename.size());
|
||||
OutputChar('"');
|
||||
|
||||
if (FileType == DirectoryLookup::SystemHeaderDir)
|
||||
OutputString(" 3", 2);
|
||||
else if (FileType == DirectoryLookup::ExternCSystemHeaderDir)
|
||||
OutputString(" 3 4", 4);
|
||||
OutputChar('\n');
|
||||
}
|
||||
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,
|
||||
DirectoryLookup::DirType FileType) {
|
||||
// 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 = FileType;
|
||||
|
||||
if (EmittedTokensOnThisLine) {
|
||||
OutputChar('\n');
|
||||
EmittedTokensOnThisLine = false;
|
||||
}
|
||||
|
||||
OutputChar('#');
|
||||
OutputChar(' ');
|
||||
|
||||
char NumberBuffer[20];
|
||||
const char *NumStr = UToStr(CurLine, NumberBuffer+20);
|
||||
OutputString(NumStr, (NumberBuffer+20)-NumStr-1);
|
||||
OutputChar(' ');
|
||||
OutputChar('"');
|
||||
OutputString(&CurFilename[0], CurFilename.size());
|
||||
OutputChar('"');
|
||||
|
||||
switch (Reason) {
|
||||
case PPCallbacks::EnterFile:
|
||||
OutputString(" 1", 2);
|
||||
break;
|
||||
case PPCallbacks::ExitFile:
|
||||
OutputString(" 2", 2);
|
||||
break;
|
||||
case PPCallbacks::SystemHeaderPragma: break;
|
||||
case PPCallbacks::RenameFile: break;
|
||||
}
|
||||
|
||||
if (FileType == DirectoryLookup::SystemHeaderDir)
|
||||
OutputString(" 3", 2);
|
||||
else if (FileType == DirectoryLookup::ExternCSystemHeaderDir)
|
||||
OutputString(" 3 4", 4);
|
||||
|
||||
OutputChar('\n');
|
||||
}
|
||||
|
||||
/// HandleIdent - Handle #ident directives when read by the preprocessor.
|
||||
///
|
||||
void PrintPPOutputPPCallbacks::Ident(SourceLocation Loc, const std::string &S) {
|
||||
MoveToLine(Loc);
|
||||
|
||||
OutputString("#ident ", strlen("#ident "));
|
||||
OutputString(&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))
|
||||
OutputChar(' ');
|
||||
|
||||
// Otherwise, indent the appropriate number of spaces.
|
||||
for (; ColNo > 1; --ColNo)
|
||||
OutputChar(' ');
|
||||
|
||||
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());
|
||||
OutputString(Prefix, strlen(Prefix));
|
||||
|
||||
// Read and print all of the pragma tokens.
|
||||
while (PragmaTok.isNot(tok::eom)) {
|
||||
if (PragmaTok.hasLeadingSpace())
|
||||
OutputChar(' ');
|
||||
std::string TokSpell = PP.getSpelling(PragmaTok);
|
||||
OutputString(&TokSpell[0], TokSpell.size());
|
||||
PP.LexUnexpandedToken(PragmaTok);
|
||||
}
|
||||
OutputChar('\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);
|
||||
|
||||
InitOutputBuffer(OutFile);
|
||||
InitAvoidConcatTokenInfo();
|
||||
|
||||
Token Tok, PrevTok;
|
||||
char Buffer[256];
|
||||
PrintPPOutputPPCallbacks *Callbacks = new PrintPPOutputPPCallbacks(PP);
|
||||
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))) {
|
||||
OutputChar(' ');
|
||||
}
|
||||
|
||||
if (IdentifierInfo *II = Tok.getIdentifierInfo()) {
|
||||
const char *Str = II->getName();
|
||||
unsigned Len = Tok.needsCleaning() ? strlen(Str) : Tok.getLength();
|
||||
OutputString(Str, Len);
|
||||
} else if (Tok.getLength() < 256) {
|
||||
const char *TokPtr = Buffer;
|
||||
unsigned Len = PP.getSpelling(Tok, TokPtr);
|
||||
OutputString(TokPtr, Len);
|
||||
} else {
|
||||
std::string S = PP.getSpelling(Tok);
|
||||
OutputString(&S[0], S.size());
|
||||
}
|
||||
Callbacks->SetEmittedTokensOnThisLine();
|
||||
|
||||
if (Tok.is(tok::eof)) break;
|
||||
|
||||
PrevTok = Tok;
|
||||
PP.Lex(Tok);
|
||||
}
|
||||
OutputChar('\n');
|
||||
|
||||
CleanupOutputBuffer(PP.getDiagnostics().hasErrorOccurred());
|
||||
}
|
||||
|
||||
@@ -1,184 +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/System/Path.h"
|
||||
#include <fstream>
|
||||
using namespace clang;
|
||||
|
||||
/// isSameToken - Return true if the two specified tokens start have the same
|
||||
/// content.
|
||||
static bool isSameToken(Token &RawTok, Token &PPTok) {
|
||||
if (PPTok.getKind() == RawTok.getKind())
|
||||
return true;
|
||||
|
||||
if (PPTok.getIdentifierInfo() &&
|
||||
PPTok.getIdentifierInfo() == RawTok.getIdentifierInfo())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void GetNextRawTok(Lexer &RawLex, Token &RawTok, Preprocessor &PP) {
|
||||
RawLex.LexRawToken(RawTok);
|
||||
|
||||
// If we have an identifier with no identifier info for our raw token, look
|
||||
// up the indentifier info.
|
||||
if (RawTok.is(tok::identifier) && !RawTok.getIdentifierInfo())
|
||||
RawTok.setIdentifierInfo(PP.LookUpIdentifierInfo(RawTok));
|
||||
}
|
||||
|
||||
/// 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());
|
||||
|
||||
const SourceManager &SourceMgr = PP.getSourceManager();
|
||||
std::pair<const char*, const char*> File =
|
||||
SourceMgr.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);
|
||||
Token RawTok;
|
||||
GetNextRawTok(RawLex, RawTok, PP);
|
||||
|
||||
// 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 bug 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 input file, but we don't want to treat them as such... just ignore
|
||||
// them.
|
||||
if (RawTok.is(tok::hash) && RawTok.isAtStartOfLine()) {
|
||||
GetNextRawTok(RawLex, RawTok, PP);
|
||||
while (!RawTok.isAtStartOfLine() && RawTok.isNot(tok::eof))
|
||||
GetNextRawTok(RawLex, RawTok, PP);
|
||||
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)) {
|
||||
GetNextRawTok(RawLex, RawTok, PP);
|
||||
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.
|
||||
RB.InsertTextAfter(RawOffs, "/*", 2);
|
||||
unsigned EndPos;
|
||||
|
||||
// Switch on comment lexing. If we get a comment, we don't want to
|
||||
// include it as part of our run of tokens, because we don't want to
|
||||
// nest /* */ comments.
|
||||
RawLex.SetCommentRetentionState(true);
|
||||
|
||||
do {
|
||||
EndPos = RawOffs+RawTok.getLength();
|
||||
|
||||
GetNextRawTok(RawLex, RawTok, PP);
|
||||
RawOffs = SM.getFullFilePos(RawTok.getLocation());
|
||||
|
||||
if (RawTok.is(tok::comment)) {
|
||||
RawLex.SetCommentRetentionState(false);
|
||||
// Skip past the comment.
|
||||
GetNextRawTok(RawLex, RawTok, PP);
|
||||
break;
|
||||
}
|
||||
|
||||
} while (RawOffs <= PPOffs && !RawTok.isAtStartOfLine() &&
|
||||
(PPOffs != RawOffs || !isSameToken(RawTok, PPTok)));
|
||||
|
||||
RawLex.SetCommentRetentionState(false);
|
||||
|
||||
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.
|
||||
std::ostream *OutFile;
|
||||
if (OutFileName == "-") {
|
||||
OutFile = llvm::cout.stream();
|
||||
} else if (!OutFileName.empty()) {
|
||||
OutFile = new std::ofstream(OutFileName.c_str(),
|
||||
std::ios_base::binary|std::ios_base::out);
|
||||
} else if (InFileName == "-") {
|
||||
OutFile = llvm::cout.stream();
|
||||
} else {
|
||||
llvm::sys::Path Path(InFileName);
|
||||
Path.eraseSuffix();
|
||||
Path.appendSuffix("cpp");
|
||||
OutFile = new std::ofstream(Path.toString().c_str(),
|
||||
std::ios_base::binary|std::ios_base::out);
|
||||
}
|
||||
|
||||
// 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");
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,197 +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.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 {
|
||||
llvm::OwningPtr<TranslationUnit> TU;
|
||||
Diagnostic &Diags;
|
||||
FileManager &FMgr;
|
||||
const LangOptions& lopts;
|
||||
public:
|
||||
SerializationTest(Diagnostic &d, FileManager& fmgr, const LangOptions& LOpts)
|
||||
: Diags(d), FMgr(fmgr), lopts(LOpts) {}
|
||||
|
||||
~SerializationTest();
|
||||
|
||||
virtual void Initialize(ASTContext& context) {
|
||||
if (!TU) TU.reset(new TranslationUnit(context, lopts));
|
||||
}
|
||||
|
||||
virtual void HandleTopLevelDecl(Decl *D) {
|
||||
TU->AddTopLevelDecl(D);
|
||||
}
|
||||
|
||||
private:
|
||||
bool Serialize(llvm::sys::Path& Filename, llvm::sys::Path& FNameDeclPrint);
|
||||
bool Deserialize(llvm::sys::Path& Filename, llvm::sys::Path& FNameDeclPrint);
|
||||
};
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
ASTConsumer*
|
||||
clang::CreateSerializationTest(Diagnostic &Diags, FileManager& FMgr,
|
||||
const LangOptions &LOpts) {
|
||||
|
||||
return new SerializationTest(Diags,FMgr,LOpts);
|
||||
}
|
||||
|
||||
|
||||
bool SerializationTest::Serialize(llvm::sys::Path& Filename,
|
||||
llvm::sys::Path& FNameDeclPrint) {
|
||||
{
|
||||
// Pretty-print the decls to a temp file.
|
||||
std::ofstream DeclPP(FNameDeclPrint.c_str());
|
||||
assert (DeclPP && "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::ofstream DeclPP(FNameDeclPrint.c_str());
|
||||
assert (DeclPP && "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);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
SerializationTest::~SerializationTest() {
|
||||
|
||||
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);
|
||||
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";
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
//===--- TextDiagnosticBuffer.cpp - Buffer Text Diagnostics ---------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This is a concrete diagnostic client, which buffers the diagnostic messages.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "TextDiagnosticBuffer.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
using namespace clang;
|
||||
|
||||
/// HandleDiagnostic - Store the errors & warnings that are reported.
|
||||
///
|
||||
void TextDiagnosticBuffer::HandleDiagnostic(Diagnostic &Diags,
|
||||
Diagnostic::Level Level,
|
||||
FullSourceLoc Pos,
|
||||
diag::kind ID,
|
||||
const std::string *Strs,
|
||||
unsigned NumStrs,
|
||||
const SourceRange *,
|
||||
unsigned) {
|
||||
switch (Level) {
|
||||
default: assert(0 && "Diagnostic not handled during diagnostic buffering!");
|
||||
case Diagnostic::Warning:
|
||||
Warnings.push_back(std::make_pair(Pos.getLocation(),
|
||||
FormatDiagnostic(Diags, Level, ID,
|
||||
Strs, NumStrs)));
|
||||
break;
|
||||
case Diagnostic::Error:
|
||||
Errors.push_back(std::make_pair(Pos.getLocation(),
|
||||
FormatDiagnostic(Diags, Level, ID,
|
||||
Strs, NumStrs)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
//===--- TextDiagnosticBuffer.h - Buffer Text Diagnostics -------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This is a concrete diagnostic client, which buffers the diagnostic messages.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef DRIVER_TEXT_DIAGNOSTIC_BUFFER_H_
|
||||
#define DRIVER_TEXT_DIAGNOSTIC_BUFFER_H_
|
||||
|
||||
#include "TextDiagnostics.h"
|
||||
#include <vector>
|
||||
|
||||
namespace clang {
|
||||
|
||||
class Preprocessor;
|
||||
class SourceManager;
|
||||
|
||||
class TextDiagnosticBuffer : public TextDiagnostics {
|
||||
public:
|
||||
typedef std::vector<std::pair<SourceLocation, std::string> > DiagList;
|
||||
typedef DiagList::iterator iterator;
|
||||
typedef DiagList::const_iterator const_iterator;
|
||||
private:
|
||||
DiagList Errors, Warnings;
|
||||
public:
|
||||
TextDiagnosticBuffer() {}
|
||||
|
||||
const_iterator err_begin() const { return Errors.begin(); }
|
||||
const_iterator err_end() const { return Errors.end(); }
|
||||
|
||||
const_iterator warn_begin() const { return Warnings.begin(); }
|
||||
const_iterator warn_end() const { return Warnings.end(); }
|
||||
|
||||
virtual void HandleDiagnostic(Diagnostic &Diags,
|
||||
Diagnostic::Level DiagLevel,
|
||||
FullSourceLoc Pos,
|
||||
diag::kind ID,
|
||||
const std::string *Strs,
|
||||
unsigned NumStrs,
|
||||
const SourceRange *Ranges,
|
||||
unsigned NumRanges);
|
||||
};
|
||||
|
||||
} // end namspace clang
|
||||
|
||||
#endif
|
||||
@@ -1,209 +0,0 @@
|
||||
//===--- TextDiagnosticPrinter.cpp - Diagnostic Printer -------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This diagnostic client prints out their diagnostic messages.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "TextDiagnosticPrinter.h"
|
||||
#include "clang/Basic/FileManager.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "clang/Lex/HeaderSearch.h"
|
||||
#include "clang/Lex/Lexer.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include <string>
|
||||
using namespace clang;
|
||||
|
||||
static llvm::cl::opt<bool>
|
||||
NoShowColumn("fno-show-column",
|
||||
llvm::cl::desc("Do not include column number on diagnostics"));
|
||||
static llvm::cl::opt<bool>
|
||||
NoCaretDiagnostics("fno-caret-diagnostics",
|
||||
llvm::cl::desc("Do not include source line and caret with"
|
||||
" diagnostics"));
|
||||
|
||||
void TextDiagnosticPrinter::
|
||||
PrintIncludeStack(FullSourceLoc Pos) {
|
||||
if (Pos.isInvalid()) return;
|
||||
|
||||
Pos = Pos.getLogicalLoc();
|
||||
|
||||
// Print out the other include frames first.
|
||||
PrintIncludeStack(Pos.getIncludeLoc());
|
||||
unsigned LineNo = Pos.getLineNumber();
|
||||
|
||||
OS << "In file included from " << Pos.getSourceName()
|
||||
<< ":" << LineNo << ":\n";
|
||||
}
|
||||
|
||||
/// HighlightRange - Given a SourceRange and a line number, highlight (with ~'s)
|
||||
/// any characters in LineNo that intersect the SourceRange.
|
||||
void TextDiagnosticPrinter::HighlightRange(const SourceRange &R,
|
||||
SourceManager& SourceMgr,
|
||||
unsigned LineNo, unsigned FileID,
|
||||
std::string &CaratLine,
|
||||
const std::string &SourceLine) {
|
||||
assert(CaratLine.size() == SourceLine.size() &&
|
||||
"Expect a correspondence between source and carat line!");
|
||||
if (!R.isValid()) return;
|
||||
|
||||
SourceLocation LogicalStart = SourceMgr.getLogicalLoc(R.getBegin());
|
||||
unsigned StartLineNo = SourceMgr.getLineNumber(LogicalStart);
|
||||
if (StartLineNo > LineNo || LogicalStart.getFileID() != FileID)
|
||||
return; // No intersection.
|
||||
|
||||
SourceLocation LogicalEnd = SourceMgr.getLogicalLoc(R.getEnd());
|
||||
unsigned EndLineNo = SourceMgr.getLineNumber(LogicalEnd);
|
||||
if (EndLineNo < LineNo || LogicalEnd.getFileID() != FileID)
|
||||
return; // No intersection.
|
||||
|
||||
// Compute the column number of the start.
|
||||
unsigned StartColNo = 0;
|
||||
if (StartLineNo == LineNo) {
|
||||
StartColNo = SourceMgr.getLogicalColumnNumber(R.getBegin());
|
||||
if (StartColNo) --StartColNo; // Zero base the col #.
|
||||
}
|
||||
|
||||
// Pick the first non-whitespace column.
|
||||
while (StartColNo < SourceLine.size() &&
|
||||
(SourceLine[StartColNo] == ' ' || SourceLine[StartColNo] == '\t'))
|
||||
++StartColNo;
|
||||
|
||||
// Compute the column number of the end.
|
||||
unsigned EndColNo = CaratLine.size();
|
||||
if (EndLineNo == LineNo) {
|
||||
EndColNo = SourceMgr.getLogicalColumnNumber(R.getEnd());
|
||||
if (EndColNo) {
|
||||
--EndColNo; // Zero base the col #.
|
||||
|
||||
// Add in the length of the token, so that we cover multi-char tokens.
|
||||
EndColNo += Lexer::MeasureTokenLength(R.getEnd(), SourceMgr);
|
||||
} else {
|
||||
EndColNo = CaratLine.size();
|
||||
}
|
||||
}
|
||||
|
||||
// Pick the last non-whitespace column.
|
||||
while (EndColNo-1 &&
|
||||
(SourceLine[EndColNo-1] == ' ' || SourceLine[EndColNo-1] == '\t'))
|
||||
--EndColNo;
|
||||
|
||||
// Fill the range with ~'s.
|
||||
assert(StartColNo <= EndColNo && "Invalid range!");
|
||||
for (unsigned i = StartColNo; i != EndColNo; ++i)
|
||||
CaratLine[i] = '~';
|
||||
}
|
||||
|
||||
void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic &Diags,
|
||||
Diagnostic::Level Level,
|
||||
FullSourceLoc Pos,
|
||||
diag::kind ID,
|
||||
const std::string *Strs,
|
||||
unsigned NumStrs,
|
||||
const SourceRange *Ranges,
|
||||
unsigned NumRanges) {
|
||||
unsigned LineNo = 0, ColNo = 0;
|
||||
unsigned FileID = 0;
|
||||
const char *LineStart = 0, *LineEnd = 0;
|
||||
|
||||
if (Pos.isValid()) {
|
||||
FullSourceLoc LPos = Pos.getLogicalLoc();
|
||||
LineNo = LPos.getLineNumber();
|
||||
FileID = LPos.getLocation().getFileID();
|
||||
|
||||
// First, if this diagnostic is not in the main file, print out the
|
||||
// "included from" lines.
|
||||
if (LastWarningLoc != LPos.getIncludeLoc()) {
|
||||
LastWarningLoc = LPos.getIncludeLoc();
|
||||
PrintIncludeStack(LastWarningLoc);
|
||||
}
|
||||
|
||||
// Compute the column number. Rewind from the current position to the start
|
||||
// of the line.
|
||||
ColNo = LPos.getColumnNumber();
|
||||
const char *TokLogicalPtr = LPos.getCharacterData();
|
||||
LineStart = TokLogicalPtr-ColNo+1; // Column # is 1-based
|
||||
|
||||
// Compute the line end. Scan forward from the error position to the end of
|
||||
// the line.
|
||||
const llvm::MemoryBuffer *Buffer = LPos.getBuffer();
|
||||
const char *BufEnd = Buffer->getBufferEnd();
|
||||
LineEnd = TokLogicalPtr;
|
||||
while (LineEnd != BufEnd &&
|
||||
*LineEnd != '\n' && *LineEnd != '\r')
|
||||
++LineEnd;
|
||||
|
||||
OS << Buffer->getBufferIdentifier() << ":" << LineNo << ":";
|
||||
if (ColNo && !NoShowColumn)
|
||||
OS << ColNo << ":";
|
||||
OS << " ";
|
||||
}
|
||||
|
||||
switch (Level) {
|
||||
default: assert(0 && "Unknown diagnostic type!");
|
||||
case Diagnostic::Note: OS << "note: "; break;
|
||||
case Diagnostic::Warning: OS << "warning: "; break;
|
||||
case Diagnostic::Error: OS << "error: "; break;
|
||||
case Diagnostic::Fatal: OS << "fatal error: "; break;
|
||||
break;
|
||||
}
|
||||
|
||||
OS << FormatDiagnostic(Diags, Level, ID, Strs, NumStrs) << "\n";
|
||||
|
||||
if (!NoCaretDiagnostics && Pos.isValid() && ((LastLoc != Pos) || Ranges)) {
|
||||
// Cache the LastLoc, it allows us to omit duplicate source/caret spewage.
|
||||
LastLoc = Pos;
|
||||
|
||||
// Get the line of the source file.
|
||||
std::string SourceLine(LineStart, LineEnd);
|
||||
|
||||
// Create a line for the carat that is filled with spaces that is the same
|
||||
// length as the line of source code.
|
||||
std::string CaratLine(LineEnd-LineStart, ' ');
|
||||
|
||||
// Highlight all of the characters covered by Ranges with ~ characters.
|
||||
for (unsigned i = 0; i != NumRanges; ++i)
|
||||
HighlightRange(Ranges[i], Pos.getManager(), LineNo, FileID,
|
||||
CaratLine, SourceLine);
|
||||
|
||||
// Next, insert the carat itself.
|
||||
if (ColNo-1 < CaratLine.size())
|
||||
CaratLine[ColNo-1] = '^';
|
||||
else
|
||||
CaratLine.push_back('^');
|
||||
|
||||
// Scan the source line, looking for tabs. If we find any, manually expand
|
||||
// them to 8 characters and update the CaratLine to match.
|
||||
for (unsigned i = 0; i != SourceLine.size(); ++i) {
|
||||
if (SourceLine[i] != '\t') continue;
|
||||
|
||||
// Replace this tab with at least one space.
|
||||
SourceLine[i] = ' ';
|
||||
|
||||
// Compute the number of spaces we need to insert.
|
||||
unsigned NumSpaces = ((i+8)&~7) - (i+1);
|
||||
assert(NumSpaces < 8 && "Invalid computation of space amt");
|
||||
|
||||
// Insert spaces into the SourceLine.
|
||||
SourceLine.insert(i+1, NumSpaces, ' ');
|
||||
|
||||
// Insert spaces or ~'s into CaratLine.
|
||||
CaratLine.insert(i+1, NumSpaces, CaratLine[i] == '~' ? '~' : ' ');
|
||||
}
|
||||
|
||||
// Finally, remove any blank spaces from the end of CaratLine.
|
||||
while (CaratLine[CaratLine.size()-1] == ' ')
|
||||
CaratLine.erase(CaratLine.end()-1);
|
||||
|
||||
// Emit what we have computed.
|
||||
OS << SourceLine << "\n";
|
||||
OS << CaratLine << "\n";
|
||||
}
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
//===--- TextDiagnosticPrinter.h - Text Diagnostic Client -------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This is a concrete diagnostic client, which prints the diagnostics to
|
||||
// standard error.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef TEXT_DIAGNOSTIC_PRINTER_H_
|
||||
#define TEXT_DIAGNOSTIC_PRINTER_H_
|
||||
|
||||
#include "TextDiagnostics.h"
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "llvm/Support/Streams.h"
|
||||
|
||||
namespace clang {
|
||||
class SourceManager;
|
||||
|
||||
class TextDiagnosticPrinter : public TextDiagnostics {
|
||||
FullSourceLoc LastWarningLoc;
|
||||
FullSourceLoc LastLoc;
|
||||
llvm::OStream OS;
|
||||
public:
|
||||
TextDiagnosticPrinter(llvm::OStream &os = llvm::cerr) : OS(os) {}
|
||||
|
||||
void PrintIncludeStack(FullSourceLoc Pos);
|
||||
|
||||
void HighlightRange(const SourceRange &R,
|
||||
SourceManager& SrcMgr,
|
||||
unsigned LineNo, unsigned FileID,
|
||||
std::string &CaratLine,
|
||||
const std::string &SourceLine);
|
||||
|
||||
virtual void HandleDiagnostic(Diagnostic &Diags,
|
||||
Diagnostic::Level DiagLevel,
|
||||
FullSourceLoc Pos,
|
||||
diag::kind ID,
|
||||
const std::string *Strs,
|
||||
unsigned NumStrs,
|
||||
const SourceRange *Ranges,
|
||||
unsigned NumRanges);
|
||||
};
|
||||
|
||||
} // end namspace clang
|
||||
|
||||
#endif
|
||||
@@ -1,53 +0,0 @@
|
||||
//===--- TextDiagnostics.cpp - Text Diagnostics Parent Class --------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This is the parent class for all text diagnostics.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "TextDiagnostics.h"
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "clang/Lex/HeaderSearch.h"
|
||||
using namespace clang;
|
||||
|
||||
TextDiagnostics:: ~TextDiagnostics() {}
|
||||
|
||||
std::string TextDiagnostics::FormatDiagnostic(Diagnostic &Diags,
|
||||
Diagnostic::Level Level,
|
||||
diag::kind ID,
|
||||
const std::string *Strs,
|
||||
unsigned NumStrs) {
|
||||
std::string Msg = Diags.getDescription(ID);
|
||||
|
||||
// Replace all instances of %0 in Msg with 'Extra'.
|
||||
for (unsigned i = 0; i < Msg.size() - 1; ++i) {
|
||||
if (Msg[i] == '%' && isdigit(Msg[i + 1])) {
|
||||
unsigned StrNo = Msg[i + 1] - '0';
|
||||
Msg = std::string(Msg.begin(), Msg.begin() + i) +
|
||||
(StrNo < NumStrs ? Strs[StrNo] : "<<<INTERNAL ERROR>>>") +
|
||||
std::string(Msg.begin() + i + 2, Msg.end());
|
||||
}
|
||||
}
|
||||
|
||||
return Msg;
|
||||
}
|
||||
|
||||
bool TextDiagnostics::isInSystemHeader(FullSourceLoc Pos) const {
|
||||
if (!Pos.isValid()) return false;
|
||||
|
||||
if (const FileEntry *F = Pos.getFileEntryForLoc()) {
|
||||
DirectoryLookup::DirType DirInfo = TheHeaderSearch->getFileDirFlavor(F);
|
||||
if (DirInfo == DirectoryLookup::SystemHeaderDir ||
|
||||
DirInfo == DirectoryLookup::ExternCSystemHeaderDir)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
//===--- TextDiagnostics.h - Text Diagnostics Checkers ----------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This is the parent class for all text diagnostics.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef TEXT_DIAGNOSTICS_H_
|
||||
#define TEXT_DIAGNOSTICS_H_
|
||||
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
|
||||
namespace clang {
|
||||
class SourceManager;
|
||||
class HeaderSearch;
|
||||
class Preprocessor;
|
||||
|
||||
class TextDiagnostics : public DiagnosticClient {
|
||||
HeaderSearch *TheHeaderSearch;
|
||||
protected:
|
||||
std::string FormatDiagnostic(Diagnostic &Diags, Diagnostic::Level Level,
|
||||
diag::kind ID,
|
||||
const std::string *Strs,
|
||||
unsigned NumStrs);
|
||||
public:
|
||||
TextDiagnostics() {}
|
||||
virtual ~TextDiagnostics();
|
||||
|
||||
void setHeaderSearch(HeaderSearch &HS) { TheHeaderSearch = &HS; }
|
||||
|
||||
virtual bool isInSystemHeader(FullSourceLoc Pos) const;
|
||||
|
||||
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 namspace clang
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,49 +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);
|
||||
|
||||
|
||||
} // 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
|
||||
|
||||
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 64.9% 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,610 +0,0 @@
|
||||
<title>"clang" CFE Internals Manual</title>
|
||||
|
||||
<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>
|
||||
-->
|
||||
@@ -1,4 +0,0 @@
|
||||
<title>'clang' C frontend documentation</title>
|
||||
|
||||
None yet, sorry :(
|
||||
|
||||
@@ -1,25 +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/DeclObjC.h"
|
||||
#include "clang/AST/Expr.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 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) {}
|
||||
|
||||
/// HandleTopLevelDecl - Handle the specified top-level declaration. This is
|
||||
/// called by HandleTopLevelDeclaration to process every top-level Decl*.
|
||||
virtual void HandleTopLevelDecl(Decl *D) {}
|
||||
|
||||
|
||||
/// HandleTopLevelDeclaration - Handle the specified top-level declaration.
|
||||
/// This is called only for Decl* that are the head of a chain of
|
||||
/// Decl's (in the case that the Decl* is a ScopedDecl*). Subclasses
|
||||
/// can override its behavior; by default it calls HandleTopLevelDecl
|
||||
/// for every Decl* in a decl chain.
|
||||
virtual void HandleTopLevelDeclaration(Decl *D);
|
||||
|
||||
|
||||
/// 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,376 +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/AST/Builtins.h"
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "clang/AST/RecordLayout.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
#include "llvm/Bitcode/SerializationFwd.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include <vector>
|
||||
|
||||
namespace clang {
|
||||
class TargetInfo;
|
||||
class IdentifierTable;
|
||||
|
||||
/// 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<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::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;
|
||||
|
||||
TranslationUnitDecl *TUDecl;
|
||||
|
||||
SourceManager &SourceMgr;
|
||||
llvm::MallocAllocator Allocator;
|
||||
public:
|
||||
TargetInfo &Target;
|
||||
IdentifierTable &Idents;
|
||||
SelectorTable &Selectors;
|
||||
|
||||
SourceManager& getSourceManager() { return SourceMgr; }
|
||||
llvm::MallocAllocator &getAllocator() { return Allocator; }
|
||||
|
||||
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 SignedCharTy, ShortTy, IntTy, LongTy, LongLongTy;
|
||||
QualType UnsignedCharTy, UnsignedShortTy, UnsignedIntTy, UnsignedLongTy;
|
||||
QualType UnsignedLongLongTy;
|
||||
QualType FloatTy, DoubleTy, LongDoubleTy;
|
||||
QualType FloatComplexTy, DoubleComplexTy, LongDoubleComplexTy;
|
||||
QualType VoidPtrTy;
|
||||
|
||||
ASTContext(SourceManager &SM, TargetInfo &t, IdentifierTable &idents,
|
||||
SelectorTable &sels, unsigned size_reserve=0 ) :
|
||||
CFConstantStringTypeDecl(0), SourceMgr(SM), Target(t),
|
||||
Idents(idents), Selectors(sels) {
|
||||
|
||||
if (size_reserve > 0) Types.reserve(size_reserve);
|
||||
InitBuiltinTypes();
|
||||
BuiltinInfo.InitializeBuiltins(idents, Target);
|
||||
TUDecl = TranslationUnitDecl::Create(*this);
|
||||
}
|
||||
|
||||
~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);
|
||||
|
||||
/// 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, QualType *ArgArray,
|
||||
unsigned NumArgs, bool isVariadic);
|
||||
|
||||
/// getTypeDeclType - Return the unique reference to the type for
|
||||
/// the specified type declaration.
|
||||
QualType getTypeDeclType(TypeDecl *Decl);
|
||||
|
||||
/// 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(QualType idType,
|
||||
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;
|
||||
|
||||
/// 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;
|
||||
}
|
||||
|
||||
// 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(ObjCMethodDecl *Decl, std::string &S);
|
||||
|
||||
/// getObjCEncodingTypeSize returns size of type for objective-c encoding
|
||||
/// purpose.
|
||||
int getObjCEncodingTypeSize(QualType t);
|
||||
|
||||
// This setter/getter repreents the ObjC 'id' type. It is setup lazily, by
|
||||
// Sema.
|
||||
void setObjCIdType(TypedefDecl *Decl);
|
||||
QualType getObjCIdType() const { return ObjCIdType; }
|
||||
|
||||
void setObjCSelType(TypedefDecl *Decl);
|
||||
QualType getObjCSelType() const { return ObjCSelType; }
|
||||
|
||||
void setObjCProtoType(QualType QT);
|
||||
QualType getObjCProtoType() const { return ObjCProtoType; }
|
||||
|
||||
void setObjCClassType(TypedefDecl *Decl);
|
||||
QualType getObjCClassType() const { return ObjCClassType; }
|
||||
|
||||
void setBuiltinVaListType(QualType T);
|
||||
QualType getBuiltinVaListType() const { return BuiltinVaListType; }
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Type Sizing and Analysis
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
/// 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);
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// 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);
|
||||
|
||||
/// 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 pointerTypesAreCompatible(QualType, QualType); // C99 6.7.5.1p2
|
||||
bool referenceTypesAreCompatible(QualType, QualType); // C++ 5.17p6
|
||||
bool functionTypesAreCompatible(QualType, QualType); // C99 6.7.5.3p15
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// 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);
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
@@ -1,234 +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 "llvm/GlobalValue.h"
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
|
||||
namespace clang {
|
||||
|
||||
/// Attr - This represents one attribute.
|
||||
class Attr {
|
||||
public:
|
||||
enum Kind {
|
||||
Aligned,
|
||||
Packed,
|
||||
Annotate,
|
||||
NoReturn,
|
||||
Deprecated,
|
||||
Weak,
|
||||
DLLImport,
|
||||
DLLExport,
|
||||
NoThrow,
|
||||
Format,
|
||||
Visibility,
|
||||
FastCall,
|
||||
StdCall,
|
||||
TransparentUnion
|
||||
};
|
||||
|
||||
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 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 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 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 {
|
||||
llvm::GlobalValue::VisibilityTypes VisibilityType;
|
||||
public:
|
||||
VisibilityAttr(llvm::GlobalValue::VisibilityTypes v) : Attr(Visibility),
|
||||
VisibilityType(v) {}
|
||||
|
||||
llvm::GlobalValue::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; }
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
@@ -1,114 +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.
|
||||
|
||||
// Standard libc/libm functions:
|
||||
BUILTIN(__builtin_inf , "d" , "nc")
|
||||
BUILTIN(__builtin_inff , "f" , "nc")
|
||||
BUILTIN(__builtin_infl , "Ld" , "nc")
|
||||
BUILTIN(__builtin_abs , "ii" , "ncF")
|
||||
BUILTIN(__builtin_fabs , "dd" , "ncF")
|
||||
BUILTIN(__builtin_fabsf, "ff" , "ncF")
|
||||
BUILTIN(__builtin_fabsl, "LdLd", "ncF")
|
||||
BUILTIN(__builtin_huge_val, "d", "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)
|
||||
|
||||
// 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_memcpy, "v*v*vC*z", "n")
|
||||
BUILTIN(__builtin_expect, "iii" , "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,89 +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_inf).
|
||||
bool isLibFunction(unsigned ID) const {
|
||||
return strchr(GetRecord(ID).Attributes, 'F') != 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,407 +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 <list>
|
||||
#include <vector>
|
||||
#include <iosfwd>
|
||||
#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();
|
||||
}
|
||||
|
||||
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(std::ostream& OS, const CFG* cfg) const;
|
||||
void printTerminator(std::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(std::ostream& OS) const;
|
||||
void dump() const;
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Internal: constructors and data.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
CFG() : Entry(NULL), Exit(NULL), IndirectGotoBlock(NULL), NumBlockIDs(0),
|
||||
BlkExprMap(NULL), BlkEdgeSet(NULL), Allocator(NULL) {};
|
||||
|
||||
~CFG();
|
||||
|
||||
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;
|
||||
|
||||
/// BlkEdgeSet - An opaque pointer to prevent inclusion of FoldingSet.h.
|
||||
/// The set contains std::pair<CFGBlock*,CFGBlock*> objects that have
|
||||
/// stable references for use by the 'BlockEdge' class. This set is intended
|
||||
/// to be sparse, as it only contains edges whether both the source
|
||||
/// and destination block have multiple successors/predecessors.
|
||||
void* BlkEdgeSet;
|
||||
|
||||
/// Alloc - An internal allocator used for BlkEdgeSet.
|
||||
void* Allocator;
|
||||
|
||||
friend class BlockEdge;
|
||||
|
||||
/// getBlockEdgeImpl - Utility method used by the class BlockEdge. The CFG
|
||||
/// stores a set of interned std::pair<CFGBlock*,CFGBlock*> that can
|
||||
/// be used by BlockEdge to refer to edges that cannot be represented
|
||||
/// by a single pointer.
|
||||
const std::pair<CFGBlock*,CFGBlock*>* getBlockEdgeImpl(const CFGBlock* B1,
|
||||
const CFGBlock* B2);
|
||||
|
||||
};
|
||||
} // 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,847 +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 interface and subclasses.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_DECL_H
|
||||
#define LLVM_CLANG_AST_DECL_H
|
||||
|
||||
#include "clang/AST/DeclBase.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);
|
||||
};
|
||||
|
||||
/// 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);
|
||||
|
||||
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:
|
||||
Expr *Init;
|
||||
// FIXME: This can be packed into the bitfields in Decl.
|
||||
unsigned SClass : 3;
|
||||
|
||||
friend class StmtIteratorBase;
|
||||
protected:
|
||||
VarDecl(Kind DK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, QualType T,
|
||||
StorageClass SC, ScopedDecl *PrevDecl)
|
||||
: ValueDecl(DK, DC, L, Id, T, PrevDecl), Init(0) { SClass = SC; }
|
||||
public:
|
||||
static VarDecl *Create(ASTContext &C, DeclContext *DC,
|
||||
SourceLocation L, IdentifierInfo *Id,
|
||||
QualType T, StorageClass S, ScopedDecl *PrevDecl);
|
||||
|
||||
StorageClass getStorageClass() const { return (StorageClass)SClass; }
|
||||
|
||||
const Expr *getInit() const { return Init; }
|
||||
Expr *getInit() { return Init; }
|
||||
void setInit(Expr *I) { Init = I; }
|
||||
|
||||
/// 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()))
|
||||
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);
|
||||
};
|
||||
|
||||
/// 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.
|
||||
|
||||
/// DeclChain - Linked list of declarations that are defined inside this
|
||||
/// function.
|
||||
ScopedDecl *DeclChain;
|
||||
|
||||
// NOTE: VC++ treats enums as signed, avoid using the StorageClass enum
|
||||
unsigned SClass : 2;
|
||||
bool IsInline : 1;
|
||||
bool IsImplicit : 1;
|
||||
|
||||
/// 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;
|
||||
|
||||
FunctionDecl(DeclContext *DC, SourceLocation L,
|
||||
IdentifierInfo *Id, QualType T,
|
||||
StorageClass S, bool isInline, ScopedDecl *PrevDecl)
|
||||
: ValueDecl(Function, DC, L, Id, T, PrevDecl),
|
||||
DeclContext(Function),
|
||||
ParamInfo(0), Body(0), DeclChain(0), SClass(S),
|
||||
IsInline(isInline), IsImplicit(0), PreviousDeclaration(0) {}
|
||||
|
||||
virtual ~FunctionDecl();
|
||||
public:
|
||||
static FunctionDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L,
|
||||
IdentifierInfo *Id, QualType T,
|
||||
StorageClass S = None, bool isInline = false,
|
||||
ScopedDecl *PrevDecl = 0);
|
||||
|
||||
/// 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;
|
||||
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; }
|
||||
|
||||
ScopedDecl *getDeclChain() const { return DeclChain; }
|
||||
void setDeclChain(ScopedDecl *D) { DeclChain = D; }
|
||||
|
||||
/// getPreviousDeclaration - Return the previous declaration of this
|
||||
/// function.
|
||||
const FunctionDecl *getPreviousDeclaration() const {
|
||||
return PreviousDeclaration;
|
||||
}
|
||||
|
||||
// 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() { return ParamInfo+param_size(); }
|
||||
param_const_iterator param_begin() const { return ParamInfo; }
|
||||
param_const_iterator param_end() const { return ParamInfo+param_size(); }
|
||||
|
||||
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 cast<FunctionType>(getType())->getResultType();
|
||||
}
|
||||
StorageClass getStorageClass() const { return StorageClass(SClass); }
|
||||
bool isInline() const { return IsInline; }
|
||||
|
||||
/// AddRedeclaration - Adds the function declaration FD as a
|
||||
/// redeclaration of this function.
|
||||
void AddRedeclaration(FunctionDecl *FD);
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return D->getKind() == Function; }
|
||||
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);
|
||||
friend void Decl::Destroy(ASTContext& C) const;
|
||||
};
|
||||
|
||||
|
||||
/// 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; }
|
||||
QualType getCanonicalType() const { return DeclType.getCanonicalType(); }
|
||||
|
||||
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 {
|
||||
Expr *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(E), Val(V) {}
|
||||
~EnumConstantDecl() {}
|
||||
public:
|
||||
|
||||
static EnumConstantDecl *Create(ASTContext &C, EnumDecl *DC,
|
||||
SourceLocation L, IdentifierInfo *Id,
|
||||
QualType T, Expr *E,
|
||||
const llvm::APSInt &V, ScopedDecl *PrevDecl);
|
||||
|
||||
const Expr *getInitExpr() const { return Init; }
|
||||
Expr *getInitExpr() { return Init; }
|
||||
const llvm::APSInt &getInitVal() const { return Val; }
|
||||
|
||||
void setInitExpr(Expr *E) { Init = 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);
|
||||
friend void Decl::Destroy(ASTContext& C) const;
|
||||
};
|
||||
|
||||
|
||||
/// 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:
|
||||
// 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) {}
|
||||
~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);
|
||||
friend void Decl::Destroy(ASTContext& C) const;
|
||||
};
|
||||
|
||||
|
||||
/// TagDecl - Represents the declaration of a struct/union/class/enum.
|
||||
class TagDecl : public TypeDecl {
|
||||
/// 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;
|
||||
}
|
||||
|
||||
const char *getKindName() const {
|
||||
switch (getKind()) {
|
||||
default: assert(0 && "Unknown TagDecl!");
|
||||
case Struct: return "struct";
|
||||
case Union: return "union";
|
||||
case Class: return "class";
|
||||
case Enum: return "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 {
|
||||
/// ElementList - this is a linked list of EnumConstantDecl's which are linked
|
||||
/// together through their getNextDeclarator pointers.
|
||||
EnumConstantDecl *ElementList;
|
||||
|
||||
/// 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) {
|
||||
ElementList = 0;
|
||||
IntegerType = QualType();
|
||||
}
|
||||
public:
|
||||
static EnumDecl *Create(ASTContext &C, DeclContext *DC,
|
||||
SourceLocation L, IdentifierInfo *Id,
|
||||
ScopedDecl *PrevDecl);
|
||||
|
||||
/// 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!");
|
||||
ElementList = 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 ElementList; }
|
||||
const EnumConstantDecl *getEnumConstantList() const { return ElementList; }
|
||||
|
||||
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.
|
||||
|
||||
RecordDecl(Kind DK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id,
|
||||
ScopedDecl *PrevDecl) : TagDecl(DK, DC, L, Id, PrevDecl) {
|
||||
HasFlexibleArrayMember = false;
|
||||
assert(classof(static_cast<Decl*>(this)) && "Invalid Kind!");
|
||||
Members = 0;
|
||||
NumMembers = -1;
|
||||
}
|
||||
public:
|
||||
|
||||
static RecordDecl *Create(ASTContext &C, Kind DK, DeclContext *DC,
|
||||
SourceLocation L, IdentifierInfo *Id,
|
||||
ScopedDecl *PrevDecl);
|
||||
|
||||
bool hasFlexibleArrayMember() const { return HasFlexibleArrayMember; }
|
||||
void setHasFlexibleArrayMember(bool V) { HasFlexibleArrayMember = V; }
|
||||
|
||||
/// 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]; }
|
||||
|
||||
/// 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(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,345 +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 FunctionDecl;
|
||||
class ObjCMethodDecl;
|
||||
class EnumDecl;
|
||||
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.
|
||||
|
||||
// Decl
|
||||
TranslationUnit,
|
||||
// NamedDecl
|
||||
Field,
|
||||
ObjCIvar,
|
||||
ObjCCategory,
|
||||
ObjCCategoryImpl,
|
||||
ObjCImplementation,
|
||||
ObjCProtocol,
|
||||
ObjCProperty,
|
||||
// ScopedDecl
|
||||
Namespace,
|
||||
// TypeDecl
|
||||
Typedef,
|
||||
// TagDecl
|
||||
Enum,
|
||||
// RecordDecl
|
||||
Struct,
|
||||
Union,
|
||||
Class,
|
||||
// ValueDecl
|
||||
EnumConstant,
|
||||
Function,
|
||||
Var,
|
||||
ParmVar,
|
||||
ObjCInterface,
|
||||
ObjCCompatibleAlias,
|
||||
ObjCMethod,
|
||||
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 = ObjCIvar,
|
||||
ScopedFirst = Namespace, ScopedLast = ParmVar,
|
||||
TypeFirst = Typedef, TypeLast = Class,
|
||||
TagFirst = Enum , TagLast = Class,
|
||||
RecordFirst = Struct , RecordLast = Class,
|
||||
ValueFirst = EnumConstant , ValueLast = ParmVar,
|
||||
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:
|
||||
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);
|
||||
|
||||
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 Typedef:
|
||||
case Function:
|
||||
case Var:
|
||||
case ParmVar:
|
||||
case EnumConstant:
|
||||
case ObjCInterface:
|
||||
case ObjCCompatibleAlias:
|
||||
return IDNS_Ordinary;
|
||||
case Struct:
|
||||
case Union:
|
||||
case Class:
|
||||
case Enum:
|
||||
return IDNS_Tag;
|
||||
case Namespace:
|
||||
return IdentifierNamespace(IDNS_Tag | IDNS_Ordinary);
|
||||
}
|
||||
}
|
||||
// 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.
|
||||
void Destroy(ASTContext& C) const;
|
||||
|
||||
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
|
||||
/// ObjCMethodDecl
|
||||
/// EnumDecl
|
||||
/// ObjCInterfaceDecl
|
||||
///
|
||||
class DeclContext {
|
||||
/// DeclKind - This indicates which class this is.
|
||||
Decl::Kind DeclKind : 8;
|
||||
|
||||
// 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::Function:
|
||||
return static_cast<FunctionDecl*>(const_cast<From*>(D));
|
||||
case Decl::ObjCMethod:
|
||||
return static_cast<ObjCMethodDecl*>(const_cast<From*>(D));
|
||||
case Decl::ObjCInterface:
|
||||
return static_cast<ObjCInterfaceDecl*>(const_cast<From*>(D));
|
||||
case Decl::Enum:
|
||||
return static_cast<EnumDecl*>(const_cast<From*>(D));
|
||||
default:
|
||||
assert(false && "a decl that inherits DeclContext isn't handled");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
DeclContext(Decl::Kind K) : DeclKind(K) {}
|
||||
|
||||
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::ObjCMethod:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// 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::Function:
|
||||
case Decl::ObjCMethod:
|
||||
case Decl::ObjCInterface:
|
||||
case Decl::Enum:
|
||||
return true;
|
||||
default:
|
||||
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 ObjCMethodDecl *D) { return true; }
|
||||
static bool classof(const EnumDecl *D) { return true; }
|
||||
static bool classof(const ObjCInterfaceDecl *D) { return true; }
|
||||
};
|
||||
|
||||
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
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,173 +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"
|
||||
|
||||
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;
|
||||
Expr *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 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 {
|
||||
Expr *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 Op; }
|
||||
Expr *getSubExpr() { return 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);
|
||||
};
|
||||
} // 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,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 <iosfwd>
|
||||
|
||||
namespace clang {
|
||||
|
||||
class Stmt;
|
||||
|
||||
class PrinterHelper {
|
||||
public:
|
||||
virtual ~PrinterHelper();
|
||||
virtual bool handledStmt(Stmt* E, std::ostream& OS) = 0;
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
@@ -1,57 +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. These objects are managed by ASTContext.
|
||||
class ASTRecordLayout {
|
||||
uint64_t Size; // Size of record in bits.
|
||||
unsigned Alignment; // Alignment of record in bits.
|
||||
uint64_t *FieldOffsets;
|
||||
friend class ASTContext;
|
||||
|
||||
ASTRecordLayout() {}
|
||||
~ASTRecordLayout() {
|
||||
delete [] FieldOffsets;
|
||||
}
|
||||
|
||||
void SetLayout(uint64_t size, unsigned alignment, uint64_t *fieldOffsets) {
|
||||
Size = size; Alignment = alignment;
|
||||
FieldOffsets = fieldOffsets;
|
||||
}
|
||||
|
||||
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 {
|
||||
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"
|
||||
#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,113 +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 , Expr)
|
||||
STMT(50, CompoundLiteralExpr , Expr)
|
||||
STMT(51, ExtVectorElementExpr , Expr)
|
||||
STMT(52, InitListExpr , Expr)
|
||||
STMT(53, 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)
|
||||
|
||||
// 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)
|
||||
|
||||
// Clang Extensions.
|
||||
STMT(76, OverloadExpr , Expr)
|
||||
|
||||
LAST_EXPR(76)
|
||||
|
||||
#undef STMT
|
||||
#undef FIRST_STMT
|
||||
#undef LAST_STMT
|
||||
#undef FIRST_EXPR
|
||||
#undef LAST_EXPR
|
||||
@@ -1,173 +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"
|
||||
|
||||
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,37 +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"
|
||||
|
||||
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,92 +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/Basic/LangOptions.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 {
|
||||
LangOptions LangOpts;
|
||||
ASTContext* Context;
|
||||
std::vector<Decl*> TopLevelDecls;
|
||||
bool OwnsMetaData;
|
||||
|
||||
// The default ctor is only invoked during deserialization.
|
||||
explicit TranslationUnit() : Context(NULL), OwnsMetaData(true) {}
|
||||
|
||||
public:
|
||||
explicit TranslationUnit(ASTContext& Ctx, const LangOptions& lopt)
|
||||
: LangOpts(lopt), Context(&Ctx), OwnsMetaData(false) {}
|
||||
|
||||
~TranslationUnit();
|
||||
|
||||
const LangOptions& getLangOpts() const { return LangOpts; }
|
||||
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 LangOpts; }
|
||||
|
||||
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);
|
||||
|
||||
/// ReadASTBitcodeFile - Reconsitute a translation unit from a bitcode file.
|
||||
TranslationUnit* ReadASTBitcodeFile(const llvm::sys::Path& Filename,
|
||||
FileManager& FMgr);
|
||||
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,422 +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.
|
||||
|
||||
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, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_cmpltps, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_cmpleps, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_cmpgtps, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_cmpgeps, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_cmpunordps, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_cmpneqps, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_cmpnltps, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_cmpnleps, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_cmpngtps, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_cmpngeps, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_cmpordps, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_cmpeqss, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_cmpltss, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_cmpless, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_cmpunordss, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_cmpneqss, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_cmpnltss, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_cmpnless, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_cmpngtss, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_cmpngess, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_cmpordss, "V4fV4fV4f", "")
|
||||
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, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_cmpltpd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_cmplepd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_cmpgtpd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_cmpgepd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_cmpunordpd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_cmpneqpd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_cmpnltpd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_cmpnlepd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_cmpngtpd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_cmpngepd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_cmpordpd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_cmpeqsd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_cmpltsd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_cmplesd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_cmpunordsd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_cmpneqsd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_cmpnltsd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_cmpnlesd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_cmpordsd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_minpd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_maxpd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_minsd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_maxsd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_andpd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_andnpd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_orpd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_xorpd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_movsd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_unpckhpd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_unpcklpd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_paddb128, "V16cV16cV16c", "")
|
||||
BUILTIN(__builtin_ia32_paddw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_paddd128, "V4iV4iV4i", "")
|
||||
BUILTIN(__builtin_ia32_paddq128, "V2LLiV2LLiV2LLi", "")
|
||||
BUILTIN(__builtin_ia32_psubb128, "V16cV16cV16c", "")
|
||||
BUILTIN(__builtin_ia32_psubw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_psubd128, "V4iV4iV4i", "")
|
||||
BUILTIN(__builtin_ia32_psubq128, "V2LLiV2LLiV2LLi", "")
|
||||
BUILTIN(__builtin_ia32_paddsb128, "V16cV16cV16c", "")
|
||||
BUILTIN(__builtin_ia32_paddsw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_psubsb128, "V16cV16cV16c", "")
|
||||
BUILTIN(__builtin_ia32_psubsw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_paddusb128, "V16cV16cV16c", "")
|
||||
BUILTIN(__builtin_ia32_paddusw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_psubusb128, "V16cV16cV16c", "")
|
||||
BUILTIN(__builtin_ia32_psubusw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_pmullw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_pmulhw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_pand128, "V2LLiV2LLiV2LLi", "")
|
||||
BUILTIN(__builtin_ia32_pandn128, "V2LLiV2LLiV2LLi", "")
|
||||
BUILTIN(__builtin_ia32_por128, "V2LLiV2LLiV2LLi", "")
|
||||
BUILTIN(__builtin_ia32_pxor128, "V2LLiV2LLiV2LLi", "")
|
||||
BUILTIN(__builtin_ia32_pavgb128, "V16cV16cV16c", "")
|
||||
BUILTIN(__builtin_ia32_pavgw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_pcmpeqb128, "V16cV16cV16c", "")
|
||||
BUILTIN(__builtin_ia32_pcmpeqw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_pcmpeqd128, "V4iV4iV4i", "")
|
||||
BUILTIN(__builtin_ia32_pcmpgtb128, "V16cV16cV16c", "")
|
||||
BUILTIN(__builtin_ia32_pcmpgtw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_pcmpgtd128, "V4iV4iV4i", "")
|
||||
BUILTIN(__builtin_ia32_pmaxub128, "V16cV16cV16c", "")
|
||||
BUILTIN(__builtin_ia32_pmaxsw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_pminub128, "V16cV16cV16c", "")
|
||||
BUILTIN(__builtin_ia32_pminsw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_punpckhbw128, "V16cV16cV16c", "")
|
||||
BUILTIN(__builtin_ia32_punpckhwd128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_punpckhdq128, "V4iV4iV4i", "")
|
||||
BUILTIN(__builtin_ia32_punpckhqdq128, "V2LLiV2LLiV2LLi", "")
|
||||
BUILTIN(__builtin_ia32_punpcklbw128, "V16cV16cV16c", "")
|
||||
BUILTIN(__builtin_ia32_punpcklwd128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_punpckldq128, "V4iV4iV4i", "")
|
||||
BUILTIN(__builtin_ia32_punpcklqdq128, "V2LLiV2LLiV2LLi", "")
|
||||
BUILTIN(__builtin_ia32_packsswb128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_packssdw128, "V4iV4iV4i", "")
|
||||
BUILTIN(__builtin_ia32_packuswb128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_pmulhuw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_addsubps, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_addsubpd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_haddps, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_haddpd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_hsubps, "V4fV4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_hsubpd, "V2dV2dV2d", "")
|
||||
BUILTIN(__builtin_ia32_phaddw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_phaddw, "V4sV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_phaddd128, "V4iV4iV4i", "")
|
||||
BUILTIN(__builtin_ia32_phaddd, "V2iV2iV2i", "")
|
||||
BUILTIN(__builtin_ia32_phaddsw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_phaddsw, "V4sV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_phsubw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_phsubw, "V4sV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_phsubd128, "V4iV4iV4i", "")
|
||||
BUILTIN(__builtin_ia32_phsubd, "V2iV2iV2i", "")
|
||||
BUILTIN(__builtin_ia32_phsubsw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_phsubsw, "V4sV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_pmaddubsw128, "V16cV16cV16c", "")
|
||||
BUILTIN(__builtin_ia32_pmaddubsw, "V8cV8cV8c", "")
|
||||
BUILTIN(__builtin_ia32_pmulhrsw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_pmulhrsw, "V4sV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_pshufb128, "V16cV16cV16c", "")
|
||||
BUILTIN(__builtin_ia32_pshufb, "V8cV8cV8c", "")
|
||||
BUILTIN(__builtin_ia32_psignb128, "V16cV16cV16c", "")
|
||||
BUILTIN(__builtin_ia32_psignb, "V8cV8cV8c", "")
|
||||
BUILTIN(__builtin_ia32_psignw128, "V8sV8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_psignw, "V4sV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_psignd128, "V4iV4iV4i", "")
|
||||
BUILTIN(__builtin_ia32_psignd, "V2iV2iV2i", "")
|
||||
BUILTIN(__builtin_ia32_pabsb128, "V16cV16c", "")
|
||||
BUILTIN(__builtin_ia32_pabsb, "V8cV8c", "")
|
||||
BUILTIN(__builtin_ia32_pabsw128, "V8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_pabsw, "V4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_pabsd128, "V4iV4i", "")
|
||||
BUILTIN(__builtin_ia32_pabsd, "V2iV2i", "")
|
||||
BUILTIN(__builtin_ia32_psllw, "V4sV4sV1LLi", "")
|
||||
BUILTIN(__builtin_ia32_pslld, "V2iV2iV1LLi", "")
|
||||
BUILTIN(__builtin_ia32_psllq, "V1LLiV1LLiV1LLi", "")
|
||||
BUILTIN(__builtin_ia32_psrlw, "V4sV4sV1LLi", "")
|
||||
BUILTIN(__builtin_ia32_psrld, "V2iV2iV1LLi", "")
|
||||
BUILTIN(__builtin_ia32_psrlq, "V1LLiV1LLiV1LLi", "")
|
||||
BUILTIN(__builtin_ia32_psraw, "V4sV4sV1LLi", "")
|
||||
BUILTIN(__builtin_ia32_psrad, "V2iV2iV1LLi", "")
|
||||
BUILTIN(__builtin_ia32_pshufw, "V4sV4si", "")
|
||||
BUILTIN(__builtin_ia32_pmaddwd, "V2iV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_packsswb, "V8cV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_packssdw, "V4sV2iV2i", "")
|
||||
BUILTIN(__builtin_ia32_packuswb, "V8cV4sV4s", "")
|
||||
BUILTIN(__builtin_ia32_ldmxcsr, "vUi", "")
|
||||
BUILTIN(__builtin_ia32_stmxcsr, "Ui", "")
|
||||
BUILTIN(__builtin_ia32_cvtpi2ps, "V4fV4fV2i", "")
|
||||
BUILTIN(__builtin_ia32_cvtps2pi, "V2iV4f", "")
|
||||
BUILTIN(__builtin_ia32_cvtsi2ss, "V4fV4fi", "")
|
||||
BUILTIN(__builtin_ia32_cvtsi642ss, "V4fV4fLLi", "")
|
||||
BUILTIN(__builtin_ia32_cvtss2si, "iV4f", "")
|
||||
BUILTIN(__builtin_ia32_cvtss2si64, "LLiV4f", "")
|
||||
BUILTIN(__builtin_ia32_cvttps2pi, "V2iV4f", "")
|
||||
BUILTIN(__builtin_ia32_cvttss2si, "iV4f", "")
|
||||
BUILTIN(__builtin_ia32_cvttss2si64, "LLiV4f", "")
|
||||
BUILTIN(__builtin_ia32_maskmovq, "vV8cV8cc*", "")
|
||||
BUILTIN(__builtin_ia32_loadups, "V4ffC*", "")
|
||||
BUILTIN(__builtin_ia32_storeups, "vf*V4f", "")
|
||||
BUILTIN(__builtin_ia32_loadhps, "V4fV4fV2i*", "")
|
||||
BUILTIN(__builtin_ia32_loadlps, "V4fV4fV2i*", "")
|
||||
BUILTIN(__builtin_ia32_storehps, "vV2i*V4f", "")
|
||||
BUILTIN(__builtin_ia32_storelps, "vV2i*V4f", "")
|
||||
BUILTIN(__builtin_ia32_movmskps, "iV4f", "")
|
||||
BUILTIN(__builtin_ia32_pmovmskb, "iV8c", "")
|
||||
BUILTIN(__builtin_ia32_movntps, "vf*V4f", "")
|
||||
BUILTIN(__builtin_ia32_movntq, "vV1LLi*V1LLi", "")
|
||||
BUILTIN(__builtin_ia32_sfence, "v", "")
|
||||
BUILTIN(__builtin_ia32_psadbw, "V4sV8cV8c", "")
|
||||
BUILTIN(__builtin_ia32_rcpps, "V4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_rcpss, "V4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_rsqrtps, "V4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_rsqrtss, "V4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_sqrtps, "V4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_sqrtss, "V4fV4f", "")
|
||||
BUILTIN(__builtin_ia32_shufps, "V4fV4fV4fi", "")
|
||||
BUILTIN(__builtin_ia32_femms, "v", "")
|
||||
BUILTIN(__builtin_ia32_pavgusb, "V8cV8cV8c", "")
|
||||
BUILTIN(__builtin_ia32_pf2id, "V2iV2f", "")
|
||||
BUILTIN(__builtin_ia32_pfacc, "V2fV2fV2f", "")
|
||||
BUILTIN(__builtin_ia32_pfadd, "V2fV2fV2f", "")
|
||||
BUILTIN(__builtin_ia32_pfcmpeq, "V2fV2fV2f", "")
|
||||
BUILTIN(__builtin_ia32_pfcmpge, "V2fV2fV2f", "")
|
||||
BUILTIN(__builtin_ia32_pfcmpgt, "V2fV2fV2f", "")
|
||||
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, "V2dd*C", "")
|
||||
BUILTIN(__builtin_ia32_storeupd, "vd*V2d", "")
|
||||
BUILTIN(__builtin_ia32_loadhpd, "V2dV2dd*C", "")
|
||||
BUILTIN(__builtin_ia32_loadlpd, "V2dV2dd*C", "")
|
||||
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, "vv*C", "")
|
||||
BUILTIN(__builtin_ia32_lfence, "v", "")
|
||||
BUILTIN(__builtin_ia32_mfence, "v", "")
|
||||
BUILTIN(__builtin_ia32_loaddqu, "V16cc*C", "")
|
||||
BUILTIN(__builtin_ia32_storedqu, "vc*CV16c", "")
|
||||
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, "V2LLiV2LLii", "")
|
||||
BUILTIN(__builtin_ia32_palignr, "V1LLiV1LLii", "")
|
||||
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, "v", "")
|
||||
BUILTIN(__builtin_ia32_vec_ext_v4hi, "v", "")
|
||||
BUILTIN(__builtin_ia32_vec_ext_v2si, "iV2ii", "")
|
||||
BUILTIN(__builtin_ia32_vec_set_v8hi, "v", "")
|
||||
BUILTIN(__builtin_ia32_vec_set_v4hi, "v", "")
|
||||
|
||||
// Apple local SSE builtins? These are probably not needed eventually, but are
|
||||
// in the apple-gcc xmmintrin.h file (rdar://4099020).
|
||||
BUILTIN(__builtin_ia32_movqv4si, "V4iV4i", "")
|
||||
BUILTIN(__builtin_ia32_loadlv4si, "V4iV2i*", "")
|
||||
BUILTIN(__builtin_ia32_storelv4si, "vV2i*V2LLi", "")
|
||||
|
||||
|
||||
#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,316 +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(CFG& cfg, const CFGBlock* B, const CFGBlock* Prev) {
|
||||
return BlockEdge(cfg,Prev,B);
|
||||
}
|
||||
|
||||
static BlockEdge NextEdge(CFG& cfg, const CFGBlock* B, const CFGBlock* Next) {
|
||||
return BlockEdge(cfg,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(CFG& cfg, const CFGBlock* B, const CFGBlock* Prev) {
|
||||
return BlockEdge(cfg,B,Prev);
|
||||
}
|
||||
|
||||
static BlockEdge NextEdge(CFG& cfg, const CFGBlock* B, const CFGBlock* Next) {
|
||||
return BlockEdge(cfg,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) {
|
||||
EnqueueFirstBlock(cfg,AnalysisDirTag());
|
||||
|
||||
while (!WorkList.isEmpty()) {
|
||||
const CFGBlock* B = WorkList.dequeue();
|
||||
ProcessMerge(cfg,B);
|
||||
ProcessBlock(B, recordStmtValues, AnalysisDirTag());
|
||||
UpdateEdges(cfg,B,TF.getVal());
|
||||
}
|
||||
}
|
||||
|
||||
void EnqueueFirstBlock(const CFG& cfg, dataflow::forward_analysis_tag) {
|
||||
WorkList.enqueue(&cfg.getEntry());
|
||||
}
|
||||
|
||||
void EnqueueFirstBlock(const CFG& cfg, dataflow::backward_analysis_tag) {
|
||||
WorkList.enqueue(&cfg.getExit());
|
||||
}
|
||||
|
||||
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(cfg,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(cfg,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,42 +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;
|
||||
|
||||
void CheckDeadStores(CFG& cfg, ASTContext &Ctx, Diagnostic &Diags);
|
||||
|
||||
void CheckUninitializedValues(CFG& cfg, ASTContext& Ctx, Diagnostic& Diags,
|
||||
bool FullUninitTaint=false);
|
||||
|
||||
GRTransferFuncs* MakeGRSimpleValsTF();
|
||||
GRTransferFuncs* MakeCFRefCountTF(ASTContext& Ctx, bool GCEnabled,
|
||||
bool StandardWarnings,
|
||||
const LangOptions& lopts);
|
||||
BugType* MakeDeadStoresChecker();
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
@@ -1,207 +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));
|
||||
}
|
||||
|
||||
const SourceRange* ranges_begin() const {
|
||||
return ranges.empty() ? NULL : &ranges[0];
|
||||
}
|
||||
|
||||
const SourceRange* 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::vector<std::string> OtherDesc;
|
||||
|
||||
public:
|
||||
PathDiagnostic() : Size(0) {}
|
||||
|
||||
PathDiagnostic(const char* desc) : Size(0), Desc(desc) {}
|
||||
|
||||
PathDiagnostic(const std::string& desc) : Size(0), Desc(desc) {}
|
||||
|
||||
~PathDiagnostic();
|
||||
|
||||
const std::string& getDescription() const { return Desc; }
|
||||
|
||||
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,67 +0,0 @@
|
||||
//=-- AnnotatedPath.h - An annotated list 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 AnnotatedPath, which represents a collection of
|
||||
// annotated ExplodedNodes.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSIS_ANNOTPATH
|
||||
#define LLVM_CLANG_ANALYSIS_ANNOTPATH
|
||||
|
||||
#include "clang/Analysis/PathSensitive/ExplodedGraph.h"
|
||||
#include <string>
|
||||
#include <list>
|
||||
|
||||
namespace clang {
|
||||
|
||||
class Expr;
|
||||
|
||||
template <typename STATE>
|
||||
class AnnotatedNode {
|
||||
ExplodedNode<STATE> *Node;
|
||||
std::string annotation;
|
||||
Expr* E;
|
||||
|
||||
public:
|
||||
AnnotatedNode(ExplodedNode<STATE>* N, const std::string& annot,
|
||||
Expr* e = NULL)
|
||||
: Node(N), annotation(annot), E(e) {}
|
||||
|
||||
ExplodedNode<STATE>* getNode() const { return Node; }
|
||||
|
||||
const std::string& getString() const { return annotation; }
|
||||
|
||||
Expr* getExpr() const { return E; }
|
||||
};
|
||||
|
||||
|
||||
template <typename STATE>
|
||||
class AnnotatedPath {
|
||||
typedef std::list<AnnotatedNode<STATE> > impl;
|
||||
impl path;
|
||||
public:
|
||||
AnnotatedPath() {}
|
||||
|
||||
void push_back(ExplodedNode<STATE>* N, const std::string& s, Expr* E = NULL) {
|
||||
path.push_back(AnnotatedNode<STATE>(N, s, E));
|
||||
}
|
||||
|
||||
typedef typename impl::iterator iterator;
|
||||
|
||||
iterator begin() { return path.begin(); }
|
||||
iterator end() { return path.end(); }
|
||||
|
||||
AnnotatedNode<STATE>& back() { return path.back(); }
|
||||
const AnnotatedNode<STATE>& back() const { return path.back(); }
|
||||
};
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
#endif
|
||||
@@ -1,84 +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);
|
||||
};
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
#endif
|
||||
@@ -1,161 +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 ValueState.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSIS_BUGREPORTER
|
||||
#define LLVM_CLANG_ANALYSIS_BUGREPORTER
|
||||
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "clang/Analysis/PathSensitive/ValueState.h"
|
||||
#include "clang/Analysis/PathSensitive/ExplodedGraph.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include <vector>
|
||||
|
||||
namespace clang {
|
||||
|
||||
class PathDiagnostic;
|
||||
class PathDiagnosticPiece;
|
||||
class PathDiagnosticClient;
|
||||
class ASTContext;
|
||||
class Diagnostic;
|
||||
class BugReporter;
|
||||
class GRExprEngine;
|
||||
class ValueState;
|
||||
class Stmt;
|
||||
class BugReport;
|
||||
|
||||
class BugType {
|
||||
public:
|
||||
BugType() {}
|
||||
virtual ~BugType();
|
||||
|
||||
virtual const char* getName() const = 0;
|
||||
virtual const char* getDescription() const { return getName(); }
|
||||
|
||||
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<ValueState>*>& Nodes) {}
|
||||
|
||||
virtual bool isCached(BugReport& R) = 0;
|
||||
};
|
||||
|
||||
class BugTypeCacheLocation : public BugType {
|
||||
llvm::SmallPtrSet<void*,10> CachedErrors;
|
||||
public:
|
||||
BugTypeCacheLocation() {}
|
||||
virtual ~BugTypeCacheLocation() {}
|
||||
virtual bool isCached(BugReport& R);
|
||||
};
|
||||
|
||||
|
||||
class BugReport {
|
||||
BugType& Desc;
|
||||
ExplodedNode<ValueState> *EndNode;
|
||||
SourceRange R;
|
||||
public:
|
||||
BugReport(BugType& D, ExplodedNode<ValueState> *n) : Desc(D), EndNode(n) {}
|
||||
virtual ~BugReport();
|
||||
|
||||
const BugType& getBugType() const { return Desc; }
|
||||
BugType& getBugType() { return Desc; }
|
||||
|
||||
ExplodedNode<ValueState>* 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 std::pair<const char**,const char**> getExtraDescriptiveText() {
|
||||
return getBugType().getExtraDescriptiveText();
|
||||
}
|
||||
|
||||
virtual PathDiagnosticPiece* getEndPath(BugReporter& BR,
|
||||
ExplodedNode<ValueState>* N);
|
||||
|
||||
virtual FullSourceLoc getLocation(SourceManager& Mgr);
|
||||
|
||||
virtual void getRanges(BugReporter& BR,const SourceRange*& beg,
|
||||
const SourceRange*& end);
|
||||
|
||||
virtual PathDiagnosticPiece* VisitNode(ExplodedNode<ValueState>* N,
|
||||
ExplodedNode<ValueState>* PrevN,
|
||||
ExplodedGraph<ValueState>& G,
|
||||
BugReporter& BR);
|
||||
};
|
||||
|
||||
class RangedBugReport : public BugReport {
|
||||
std::vector<SourceRange> Ranges;
|
||||
public:
|
||||
RangedBugReport(BugType& D, ExplodedNode<ValueState> *n)
|
||||
: BugReport(D, n) {}
|
||||
|
||||
virtual ~RangedBugReport();
|
||||
|
||||
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 BugReporter {
|
||||
Diagnostic& Diag;
|
||||
PathDiagnosticClient* PD;
|
||||
ASTContext& Ctx;
|
||||
GRExprEngine& Eng;
|
||||
|
||||
public:
|
||||
BugReporter(Diagnostic& diag, PathDiagnosticClient* pd,
|
||||
ASTContext& ctx, GRExprEngine& eng)
|
||||
: Diag(diag), PD(pd), Ctx(ctx), Eng(eng) {}
|
||||
|
||||
~BugReporter();
|
||||
|
||||
Diagnostic& getDiagnostic() { return Diag; }
|
||||
|
||||
PathDiagnosticClient* getDiagnosticClient() { return PD; }
|
||||
|
||||
ASTContext& getContext() { return Ctx; }
|
||||
|
||||
SourceManager& getSourceManager() { return Ctx.getSourceManager(); }
|
||||
|
||||
ExplodedGraph<ValueState>& getGraph();
|
||||
|
||||
GRExprEngine& getEngine() { return Eng; }
|
||||
|
||||
CFG& getCFG() { return getGraph().getCFG(); }
|
||||
|
||||
void EmitWarning(BugReport& R);
|
||||
|
||||
void GeneratePathDiagnostic(PathDiagnostic& PD, BugReport& R);
|
||||
};
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
#endif
|
||||
@@ -1,516 +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. Normally this value
|
||||
/// is immutable, but we anticipate there will be times when algorithms
|
||||
/// that directly manipulate the analysis graph will need to change it.
|
||||
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, 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) {
|
||||
assert (!V->isSink());
|
||||
Preds.addNode(V);
|
||||
V->Succs.addNode(this);
|
||||
}
|
||||
|
||||
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(); }
|
||||
};
|
||||
|
||||
|
||||
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, StateTy* St)
|
||||
: ExplodedNodeImpl(loc, St) {}
|
||||
|
||||
/// getState - Returns the state associated with the node.
|
||||
inline StateTy* getState() const {
|
||||
return static_cast<StateTy*>(State);
|
||||
}
|
||||
|
||||
// Profiling (for FoldingSet).
|
||||
|
||||
static inline void Profile(llvm::FoldingSetNodeID& ID,
|
||||
const ProgramPoint& Loc,
|
||||
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, 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,
|
||||
void* State, bool* IsNew) {
|
||||
|
||||
return getNode(L, static_cast<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, 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,38 +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;
|
||||
|
||||
virtual ~GRAuditor() {}
|
||||
virtual bool Audit(NodeTy* N) = 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,634 +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;
|
||||
|
||||
typedef llvm::DenseMap<Stmt*,Stmt*> ParentMapTy;
|
||||
|
||||
/// G - The simulation graph. Each node is a (location,state) pair.
|
||||
llvm::OwningPtr<ExplodedGraphImpl> G;
|
||||
|
||||
/// ParentMap - A lazily populated map from a Stmt* to its parent Stmt*.
|
||||
void* ParentMap;
|
||||
|
||||
/// CurrentBlkExpr - The current Block-level expression being processed.
|
||||
/// This is used when lazily populating ParentMap.
|
||||
Stmt* CurrentBlkExpr;
|
||||
|
||||
/// 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, void* State,
|
||||
ExplodedNodeImpl* Pred = NULL);
|
||||
|
||||
/// 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 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, 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, void* State,
|
||||
ExplodedNodeImpl* Pred,
|
||||
bool isLoad = false);
|
||||
|
||||
inline ExplodedNodeImpl* generateNodeImpl(Stmt* S, void* State,
|
||||
bool isLoad = false) {
|
||||
ExplodedNodeImpl* N = getLastNode();
|
||||
assert (N && "Predecessor of new node is infeasible.");
|
||||
return generateNodeImpl(S, State, N, isLoad);
|
||||
}
|
||||
|
||||
Stmt* getStmt() const { return B[Idx]; }
|
||||
|
||||
CFGBlock* getBlock() const { return &B; }
|
||||
};
|
||||
|
||||
|
||||
template<typename STATE>
|
||||
class GRStmtNodeBuilder {
|
||||
typedef STATE StateTy;
|
||||
typedef ExplodedNode<StateTy> NodeTy;
|
||||
|
||||
GRStmtNodeBuilderImpl& NB;
|
||||
StateTy* CleanedState;
|
||||
|
||||
GRAuditor<StateTy> **CallExprAuditBeg, **CallExprAuditEnd;
|
||||
GRAuditor<StateTy> **ObjCMsgExprAuditBeg, **ObjCMsgExprAuditEnd;
|
||||
|
||||
public:
|
||||
GRStmtNodeBuilder(GRStmtNodeBuilderImpl& nb) : NB(nb),
|
||||
CallExprAuditBeg(0), CallExprAuditEnd(0),
|
||||
ObjCMsgExprAuditBeg(0), ObjCMsgExprAuditEnd(0),
|
||||
BuildSinks(false), HasGeneratedNode(false) {
|
||||
|
||||
CleanedState = getLastNode()->getState();
|
||||
}
|
||||
|
||||
void setObjCMsgExprAuditors(GRAuditor<StateTy> **B,
|
||||
GRAuditor<StateTy> **E) {
|
||||
ObjCMsgExprAuditBeg = B;
|
||||
ObjCMsgExprAuditEnd = E;
|
||||
}
|
||||
|
||||
void setCallExprAuditors(GRAuditor<StateTy> **B,
|
||||
GRAuditor<StateTy> **E) {
|
||||
CallExprAuditBeg = B;
|
||||
CallExprAuditEnd = E;
|
||||
}
|
||||
|
||||
NodeTy* getLastNode() const {
|
||||
return static_cast<NodeTy*>(NB.getLastNode());
|
||||
}
|
||||
|
||||
NodeTy* generateNode(Stmt* S, StateTy* St, NodeTy* Pred, bool isLoad = false){
|
||||
HasGeneratedNode = true;
|
||||
return static_cast<NodeTy*>(NB.generateNodeImpl(S, St, Pred, isLoad));
|
||||
}
|
||||
|
||||
NodeTy* generateNode(Stmt* S, StateTy* St, bool isLoad = false) {
|
||||
HasGeneratedNode = true;
|
||||
return static_cast<NodeTy*>(NB.generateNodeImpl(S, St, isLoad));
|
||||
}
|
||||
|
||||
GRBlockCounter getBlockCounter() const {
|
||||
return NB.getBlockCounter();
|
||||
}
|
||||
|
||||
unsigned getCurrentBlockCount() const {
|
||||
return NB.getCurrentBlockCount();
|
||||
}
|
||||
|
||||
StateTy* GetState(NodeTy* Pred) const {
|
||||
if ((ExplodedNodeImpl*) Pred == NB.getBasePredecessor())
|
||||
return CleanedState;
|
||||
else
|
||||
return Pred->getState();
|
||||
}
|
||||
|
||||
void SetCleanedState(StateTy* St) {
|
||||
CleanedState = St;
|
||||
}
|
||||
|
||||
NodeTy* MakeNode(ExplodedNodeSet<StateTy>& Dst, Stmt* S,
|
||||
NodeTy* Pred, StateTy* St) {
|
||||
|
||||
StateTy* PredState = GetState(Pred);
|
||||
|
||||
GRAuditor<StateTy> **AB = NULL, **AE = NULL;
|
||||
|
||||
switch (S->getStmtClass()) {
|
||||
default: break;
|
||||
case Stmt::CallExprClass:
|
||||
AB = CallExprAuditBeg;
|
||||
AE = CallExprAuditEnd;
|
||||
break;
|
||||
case Stmt::ObjCMessageExprClass:
|
||||
AB = ObjCMsgExprAuditBeg;
|
||||
AE = ObjCMsgExprAuditEnd;
|
||||
break;
|
||||
}
|
||||
|
||||
// If the state hasn't changed, don't generate a new node.
|
||||
if (!BuildSinks && St == PredState && AB == NULL) {
|
||||
Dst.Add(Pred);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
NodeTy* N = generateNode(S, St, Pred);
|
||||
|
||||
if (N) {
|
||||
if (BuildSinks)
|
||||
N->markAsSink();
|
||||
else {
|
||||
for ( ; AB != AE; ++AB)
|
||||
if ((*AB)->Audit(N))
|
||||
N->markAsSink();
|
||||
|
||||
Dst.Add(N);
|
||||
}
|
||||
}
|
||||
|
||||
return N;
|
||||
}
|
||||
|
||||
bool BuildSinks;
|
||||
bool HasGeneratedNode;
|
||||
};
|
||||
|
||||
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(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());
|
||||
}
|
||||
|
||||
StateTy* getState() const {
|
||||
return getPredecessor()->getState();
|
||||
}
|
||||
|
||||
inline NodeTy* generateNode(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);
|
||||
}
|
||||
|
||||
inline 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, void* State,
|
||||
bool isSink);
|
||||
|
||||
inline Expr* getTarget() const { return E; }
|
||||
inline 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;
|
||||
|
||||
inline iterator begin() { return NB.begin(); }
|
||||
inline iterator end() { return NB.end(); }
|
||||
|
||||
inline Expr* getTarget() const { return NB.getTarget(); }
|
||||
|
||||
inline NodeTy* generateNode(const iterator& I, StateTy* St, bool isSink=false){
|
||||
return static_cast<NodeTy*>(NB.generateNodeImpl(I, St, isSink));
|
||||
}
|
||||
|
||||
inline StateTy* getState() const {
|
||||
return static_cast<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, void* State);
|
||||
ExplodedNodeImpl* generateDefaultCaseNodeImpl(void* State, bool isSink);
|
||||
|
||||
inline Expr* getCondition() const { return Condition; }
|
||||
inline 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;
|
||||
|
||||
inline iterator begin() { return NB.begin(); }
|
||||
inline iterator end() { return NB.end(); }
|
||||
|
||||
inline Expr* getCondition() const { return NB.getCondition(); }
|
||||
|
||||
inline NodeTy* generateCaseStmtNode(const iterator& I, StateTy* St) {
|
||||
return static_cast<NodeTy*>(NB.generateCaseStmtNodeImpl(I, St));
|
||||
}
|
||||
|
||||
inline NodeTy* generateDefaultCaseNode(StateTy* St, bool isSink = false) {
|
||||
return static_cast<NodeTy*>(NB.generateDefaultCaseNodeImpl(St, isSink));
|
||||
}
|
||||
|
||||
inline StateTy* getState() const {
|
||||
return static_cast<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(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();
|
||||
}
|
||||
|
||||
StateTy* getState() const {
|
||||
return getPredecessor()->getState();
|
||||
}
|
||||
|
||||
NodeTy* MakeNode(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 ExplodedGraph<StateTy> GraphTy;
|
||||
typedef typename GraphTy::NodeTy NodeTy;
|
||||
|
||||
protected:
|
||||
SubEngineTy& SubEngine;
|
||||
|
||||
virtual 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.ProcessStmt(S, Builder);
|
||||
}
|
||||
|
||||
virtual bool ProcessBlockEntrance(CFGBlock* Blk, void* State,
|
||||
GRBlockCounter BC) {
|
||||
return SubEngine.ProcessBlockEntrance(Blk, static_cast<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,654 +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/ValueState.h"
|
||||
#include "clang/Analysis/PathSensitive/GRSimpleAPICheck.h"
|
||||
#include "clang/Analysis/PathSensitive/GRTransferFuncs.h"
|
||||
#include "clang/AST/Type.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
class BugType;
|
||||
class PathDiagnosticClient;
|
||||
class Diagnostic;
|
||||
|
||||
class GRExprEngine {
|
||||
|
||||
public:
|
||||
typedef ValueState 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 ValueStateManager::RemoveDeadBindings.
|
||||
ValueStateManager::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.
|
||||
ValueStateManager StateMgr;
|
||||
|
||||
/// ValueMgr - Object that manages the data for all created RVals.
|
||||
BasicValueFactory& BasicVals;
|
||||
|
||||
/// TF - Object that represents a bundle of transfer functions
|
||||
/// for manipulating and creating RVals.
|
||||
GRTransferFuncs* TF;
|
||||
|
||||
/// 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).
|
||||
ValueState* CleanedState;
|
||||
|
||||
/// CurrentStmt - The current block-level statement.
|
||||
Stmt* CurrentStmt;
|
||||
|
||||
// Obj-C Class Identifiers.
|
||||
IdentifierInfo* NSExceptionII;
|
||||
|
||||
// Obj-C Selectors.
|
||||
Selector* NSExceptionInstanceRaiseSelectors;
|
||||
Selector RaiseSel;
|
||||
|
||||
typedef llvm::SmallVector<GRSimpleAPICheck*,2> SimpleChecksTy;
|
||||
|
||||
SimpleChecksTy CallChecks;
|
||||
SimpleChecksTy MsgExprChecks;
|
||||
|
||||
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);
|
||||
~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(); }
|
||||
|
||||
/// 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.
|
||||
ValueState* 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(); }
|
||||
|
||||
void Register(BugType* B) {
|
||||
BugTypes.push_back(B);
|
||||
}
|
||||
|
||||
void EmitWarnings(Diagnostic& Diag, PathDiagnosticClient* PD);
|
||||
|
||||
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(); }
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
typedef SimpleChecksTy::iterator simple_checks_iterator;
|
||||
|
||||
simple_checks_iterator call_auditors_begin() { return CallChecks.begin(); }
|
||||
simple_checks_iterator call_auditors_end() { return CallChecks.end(); }
|
||||
|
||||
simple_checks_iterator msgexpr_auditors_begin() {
|
||||
return MsgExprChecks.begin();
|
||||
}
|
||||
simple_checks_iterator msgexpr_auditors_end() {
|
||||
return MsgExprChecks.end();
|
||||
}
|
||||
|
||||
void AddCallCheck(GRSimpleAPICheck* A);
|
||||
|
||||
void AddObjCMessageExprCheck(GRSimpleAPICheck* A);
|
||||
|
||||
/// 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, ValueState* 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) {
|
||||
TF->EvalEndPath(*this, builder);
|
||||
}
|
||||
|
||||
ValueStateManager& getStateManager() { return StateMgr; }
|
||||
const ValueStateManager& getStateManger() const { return StateMgr; }
|
||||
|
||||
BasicValueFactory& getBasicVals() { return BasicVals; }
|
||||
const BasicValueFactory& getBasicVals() const { return BasicVals; }
|
||||
|
||||
SymbolManager& getSymbolManager() { return SymMgr; }
|
||||
const SymbolManager& getSymbolManager() const { return SymMgr; }
|
||||
|
||||
protected:
|
||||
|
||||
ValueState* GetState(NodeTy* N) {
|
||||
return N == EntryNode ? CleanedState : N->getState();
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
// FIXME: Maybe make these accesible only within the StmtBuilder?
|
||||
|
||||
ValueState* SetRVal(ValueState* St, Expr* Ex, RVal V);
|
||||
|
||||
ValueState* SetRVal(ValueState* St, const Expr* Ex, RVal V) {
|
||||
return SetRVal(St, const_cast<Expr*>(Ex), V);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
ValueState* SetBlkExprRVal(ValueState* St, Expr* Ex, RVal V) {
|
||||
return StateMgr.SetRVal(St, Ex, V, true, false);
|
||||
}
|
||||
|
||||
ValueState* SetRVal(ValueState* St, LVal LV, RVal V) {
|
||||
return StateMgr.SetRVal(St, LV, V);
|
||||
}
|
||||
|
||||
RVal GetRVal(ValueState* St, Expr* Ex) {
|
||||
return StateMgr.GetRVal(St, Ex);
|
||||
}
|
||||
|
||||
RVal GetRVal(ValueState* St, const Expr* Ex) {
|
||||
return GetRVal(St, const_cast<Expr*>(Ex));
|
||||
}
|
||||
|
||||
RVal GetBlkExprRVal(ValueState* St, Expr* Ex) {
|
||||
return StateMgr.GetBlkExprRVal(St, Ex);
|
||||
}
|
||||
|
||||
RVal GetRVal(ValueState* St, LVal LV, QualType T = QualType()) {
|
||||
return StateMgr.GetRVal(St, LV, T);
|
||||
}
|
||||
|
||||
inline NonLVal MakeConstantVal(uint64_t X, Expr* Ex) {
|
||||
return NonLVal::MakeVal(BasicVals, X, Ex->getType());
|
||||
}
|
||||
|
||||
/// Assume - Create new state by assuming that a given expression
|
||||
/// is true or false.
|
||||
ValueState* Assume(ValueState* St, RVal Cond, bool Assumption,
|
||||
bool& isFeasible) {
|
||||
|
||||
if (Cond.isUnknown()) {
|
||||
isFeasible = true;
|
||||
return St;
|
||||
}
|
||||
|
||||
if (isa<LVal>(Cond))
|
||||
return Assume(St, cast<LVal>(Cond), Assumption, isFeasible);
|
||||
else
|
||||
return Assume(St, cast<NonLVal>(Cond), Assumption, isFeasible);
|
||||
}
|
||||
|
||||
ValueState* Assume(ValueState* St, LVal Cond, bool Assumption,
|
||||
bool& isFeasible);
|
||||
|
||||
ValueState* AssumeAux(ValueState* St, LVal Cond, bool Assumption,
|
||||
bool& isFeasible);
|
||||
|
||||
ValueState* Assume(ValueState* St, NonLVal Cond, bool Assumption,
|
||||
bool& isFeasible);
|
||||
|
||||
ValueState* AssumeAux(ValueState* St, NonLVal Cond, bool Assumption,
|
||||
bool& isFeasible);
|
||||
|
||||
ValueState* AssumeSymNE(ValueState* St, SymbolID sym, const llvm::APSInt& V,
|
||||
bool& isFeasible);
|
||||
|
||||
ValueState* AssumeSymEQ(ValueState* St, SymbolID sym, const llvm::APSInt& V,
|
||||
bool& isFeasible);
|
||||
|
||||
ValueState* AssumeSymInt(ValueState* St, bool Assumption,
|
||||
const SymIntConstraint& C, bool& isFeasible);
|
||||
|
||||
NodeTy* MakeNode(NodeSet& Dst, Stmt* S, NodeTy* Pred, ValueState* St) {
|
||||
assert (Builder && "GRStmtNodeBuilder not present.");
|
||||
return Builder->MakeNode(Dst, S, Pred, St);
|
||||
}
|
||||
|
||||
/// 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);
|
||||
|
||||
void VisitDeclStmtAux(DeclStmt* DS, ScopedDecl* D,
|
||||
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, ValueState* St, NodeTy* Pred, RVal Denom);
|
||||
|
||||
RVal EvalCast(RVal X, QualType CastT) {
|
||||
if (X.isUnknownOrUndef())
|
||||
return X;
|
||||
|
||||
if (isa<LVal>(X))
|
||||
return TF->EvalCast(*this, cast<LVal>(X), CastT);
|
||||
else
|
||||
return TF->EvalCast(*this, cast<NonLVal>(X), CastT);
|
||||
}
|
||||
|
||||
RVal EvalMinus(UnaryOperator* U, RVal X) {
|
||||
return X.isValid() ? TF->EvalMinus(*this, U, cast<NonLVal>(X)) : X;
|
||||
}
|
||||
|
||||
RVal EvalComplement(RVal X) {
|
||||
return X.isValid() ? TF->EvalComplement(*this, cast<NonLVal>(X)) : X;
|
||||
}
|
||||
|
||||
RVal EvalBinOp(BinaryOperator::Opcode Op, NonLVal L, RVal R) {
|
||||
return R.isValid() ? TF->EvalBinOp(*this, Op, L, cast<NonLVal>(R)) : R;
|
||||
}
|
||||
|
||||
RVal EvalBinOp(BinaryOperator::Opcode Op, NonLVal L, NonLVal R) {
|
||||
return R.isValid() ? TF->EvalBinOp(*this, Op, L, R) : 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 TF->EvalBinOp(*this, Op, cast<LVal>(L), cast<LVal>(R));
|
||||
else
|
||||
return TF->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 TF->EvalBinOp(*this, Op, cast<LVal>(R), cast<NonLVal>(L));
|
||||
}
|
||||
else
|
||||
return TF->EvalBinOp(*this, Op, cast<NonLVal>(L), cast<NonLVal>(R));
|
||||
}
|
||||
|
||||
void EvalCall(NodeSet& Dst, CallExpr* CE, RVal L, NodeTy* Pred) {
|
||||
assert (Builder && "GRStmtNodeBuilder must be defined.");
|
||||
TF->EvalCall(Dst, *this, *Builder, CE, L, Pred);
|
||||
}
|
||||
|
||||
void EvalObjCMessageExpr(NodeSet& Dst, ObjCMessageExpr* ME, NodeTy* Pred) {
|
||||
assert (Builder && "GRStmtNodeBuilder must be defined.");
|
||||
TF->EvalObjCMessageExpr(Dst, *this, *Builder, ME, Pred);
|
||||
}
|
||||
|
||||
void EvalStore(NodeSet& Dst, Expr* E, NodeTy* Pred, ValueState* 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,
|
||||
ValueState* St, RVal location, bool CheckOnly = false);
|
||||
|
||||
ValueState* EvalLocation(Expr* Ex, NodeTy* Pred,
|
||||
ValueState* St, RVal location, bool isLoad = false);
|
||||
|
||||
void EvalReturn(NodeSet& Dst, ReturnStmt* s, NodeTy* Pred);
|
||||
|
||||
ValueState* MarkBranch(ValueState* 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"
|
||||
|
||||
namespace clang {
|
||||
|
||||
class ValueState;
|
||||
class Diagnostic;
|
||||
class BugReporter;
|
||||
class ASTContext;
|
||||
class GRExprEngine;
|
||||
class PathDiagnosticClient;
|
||||
template <typename T> class ExplodedGraph;
|
||||
|
||||
|
||||
class GRSimpleAPICheck : public GRAuditor<ValueState> {
|
||||
public:
|
||||
GRSimpleAPICheck() {}
|
||||
virtual ~GRSimpleAPICheck() {}
|
||||
virtual void EmitWarnings(BugReporter& BR) = 0;
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
@@ -1,119 +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/ValueState.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
class GRExprEngine;
|
||||
|
||||
class GRTransferFuncs {
|
||||
public:
|
||||
GRTransferFuncs() {}
|
||||
virtual ~GRTransferFuncs() {}
|
||||
|
||||
virtual ValueState::CheckerStatePrinter* getCheckerStatePrinter() {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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 RVal EvalBinOp(GRExprEngine& Engine, BinaryOperator::Opcode Op,
|
||||
NonLVal L, NonLVal R) = 0;
|
||||
|
||||
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<ValueState>& Dst,
|
||||
GRExprEngine& Engine,
|
||||
GRStmtNodeBuilder<ValueState>& Builder,
|
||||
CallExpr* CE, RVal L,
|
||||
ExplodedNode<ValueState>* Pred) {}
|
||||
|
||||
virtual void EvalObjCMessageExpr(ExplodedNodeSet<ValueState>& Dst,
|
||||
GRExprEngine& Engine,
|
||||
GRStmtNodeBuilder<ValueState>& Builder,
|
||||
ObjCMessageExpr* ME,
|
||||
ExplodedNode<ValueState>* 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<ValueState>& Dst,
|
||||
GRExprEngine& Engine,
|
||||
GRStmtNodeBuilder<ValueState>& Builder,
|
||||
Expr* E, ExplodedNode<ValueState>* Pred,
|
||||
ValueState* St, RVal TargetLV, RVal Val);
|
||||
|
||||
|
||||
// End-of-path and dead symbol notification.
|
||||
|
||||
virtual void EvalEndPath(GRExprEngine& Engine,
|
||||
GREndPathNodeBuilder<ValueState>& Builder) {}
|
||||
|
||||
|
||||
virtual void EvalDeadSymbols(ExplodedNodeSet<ValueState>& Dst,
|
||||
GRExprEngine& Engine,
|
||||
GRStmtNodeBuilder<ValueState>& Builder,
|
||||
ExplodedNode<ValueState>* Pred,
|
||||
Stmt* S,
|
||||
ValueState* St,
|
||||
const ValueStateManager::DeadSymbolsTy& Dead) {}
|
||||
|
||||
// Return statements.
|
||||
|
||||
virtual void EvalReturn(ExplodedNodeSet<ValueState>& Dst,
|
||||
GRExprEngine& Engine,
|
||||
GRStmtNodeBuilder<ValueState>& Builder,
|
||||
ReturnStmt* S,
|
||||
ExplodedNode<ValueState>* Pred) {}
|
||||
|
||||
// Assumptions.
|
||||
|
||||
virtual ValueState* EvalAssume(GRExprEngine& Engine, ValueState* 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,507 +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 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;
|
||||
}
|
||||
|
||||
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(BasicValueFactory& BasicVals, 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();
|
||||
}
|
||||
};
|
||||
|
||||
//==------------------------------------------------------------------------==//
|
||||
// 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, DeclValKind, 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 DeclVal : public LVal {
|
||||
public:
|
||||
DeclVal(const VarDecl* vd) : LVal(DeclValKind, vd) {}
|
||||
|
||||
VarDecl* getDecl() const {
|
||||
return static_cast<VarDecl*>(Data);
|
||||
}
|
||||
|
||||
inline bool operator==(const DeclVal& R) const {
|
||||
return getDecl() == R.getDecl();
|
||||
}
|
||||
|
||||
inline bool operator!=(const DeclVal& R) const {
|
||||
return getDecl() != R.getDecl();
|
||||
}
|
||||
|
||||
// Implement isa<T> support.
|
||||
static inline bool classof(const RVal* V) {
|
||||
return V->getBaseKind() == LValKind &&
|
||||
V->getSubKind() == DeclValKind;
|
||||
}
|
||||
|
||||
static inline bool classof(const LVal* V) {
|
||||
return V->getSubKind() == DeclValKind;
|
||||
}
|
||||
};
|
||||
|
||||
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,257 +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;
|
||||
unsigned Count;
|
||||
|
||||
public:
|
||||
SymbolConjured(SymbolID Sym, Expr* exp, unsigned count)
|
||||
: SymbolData(ConjuredKind, Sym), E(exp), Count(count) {}
|
||||
|
||||
Expr* getExpr() const { return E; }
|
||||
unsigned getCount() const { return Count; }
|
||||
|
||||
static void Profile(llvm::FoldingSetNodeID& profile,
|
||||
Expr* E, unsigned Count) {
|
||||
|
||||
profile.AddInteger((unsigned) ConjuredKind);
|
||||
profile.AddPointer(E);
|
||||
profile.AddInteger(Count);
|
||||
}
|
||||
|
||||
virtual void Profile(llvm::FoldingSetNodeID& profile) {
|
||||
Profile(profile, E, 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, unsigned VisitCount);
|
||||
|
||||
const SymbolData& getSymbolData(SymbolID ID) const;
|
||||
|
||||
QualType getType(SymbolID ID) const {
|
||||
return getSymbolData(ID).getType(*this);
|
||||
}
|
||||
};
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
#endif
|
||||
@@ -1,260 +0,0 @@
|
||||
//== ValueState*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 ValueState*
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSIS_VALUESTATE_H
|
||||
#define LLVM_CLANG_ANALYSIS_VALUESTATE_H
|
||||
|
||||
// FIXME: Reduce the number of includes.
|
||||
|
||||
#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/SmallPtrSet.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 {
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// ValueState- An ImmutableMap type Stmt*/Decl*/Symbols to RVals.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// ValueState - 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 ValueState : public llvm::FoldingSetNode {
|
||||
public:
|
||||
|
||||
// Typedefs.
|
||||
|
||||
typedef llvm::ImmutableSet<llvm::APSInt*> IntSetTy;
|
||||
typedef llvm::ImmutableMap<Expr*,RVal> ExprBindingsTy;
|
||||
typedef llvm::ImmutableMap<VarDecl*,RVal> VarBindingsTy;
|
||||
typedef llvm::ImmutableMap<SymbolID,IntSetTy> ConstNotEqTy;
|
||||
typedef llvm::ImmutableMap<SymbolID,const llvm::APSInt*> ConstEqTy;
|
||||
|
||||
private:
|
||||
|
||||
void operator=(const ValueState& R) const;
|
||||
|
||||
// FIXME: Make these private.
|
||||
|
||||
public:
|
||||
ExprBindingsTy SubExprBindings;
|
||||
ExprBindingsTy BlockExprBindings;
|
||||
VarBindingsTy VarBindings;
|
||||
ConstNotEqTy ConstNotEq;
|
||||
ConstEqTy ConstEq;
|
||||
void* CheckerState;
|
||||
|
||||
public:
|
||||
|
||||
/// This ctor is used when creating the first ValueState object.
|
||||
ValueState(ExprBindingsTy EB, VarBindingsTy VB,
|
||||
ConstNotEqTy CNE, ConstEqTy CE)
|
||||
: SubExprBindings(EB),
|
||||
BlockExprBindings(EB),
|
||||
VarBindings(VB),
|
||||
ConstNotEq(CNE),
|
||||
ConstEq(CE),
|
||||
CheckerState(NULL) {}
|
||||
|
||||
/// Copy ctor - We must explicitly define this or else the "Next" ptr
|
||||
/// in FoldingSetNode will also get copied.
|
||||
ValueState(const ValueState& RHS)
|
||||
: llvm::FoldingSetNode(),
|
||||
SubExprBindings(RHS.SubExprBindings),
|
||||
BlockExprBindings(RHS.BlockExprBindings),
|
||||
VarBindings(RHS.VarBindings),
|
||||
ConstNotEq(RHS.ConstNotEq),
|
||||
ConstEq(RHS.ConstEq),
|
||||
CheckerState(RHS.CheckerState) {}
|
||||
|
||||
/// Profile - Profile the contents of a ValueState object for use
|
||||
/// in a FoldingSet.
|
||||
static void Profile(llvm::FoldingSetNodeID& ID, const ValueState* V) {
|
||||
V->SubExprBindings.Profile(ID);
|
||||
V->BlockExprBindings.Profile(ID);
|
||||
V->VarBindings.Profile(ID);
|
||||
V->ConstNotEq.Profile(ID);
|
||||
V->ConstEq.Profile(ID);
|
||||
ID.AddPointer(V->CheckerState);
|
||||
}
|
||||
|
||||
/// Profile - Used to profile the contents of this object for inclusion
|
||||
/// in a FoldingSet.
|
||||
void Profile(llvm::FoldingSetNodeID& ID) const {
|
||||
Profile(ID, this);
|
||||
}
|
||||
|
||||
// Queries.
|
||||
|
||||
bool isNotEqual(SymbolID sym, const llvm::APSInt& V) const;
|
||||
const llvm::APSInt* getSymVal(SymbolID sym) const;
|
||||
|
||||
// Iterators.
|
||||
|
||||
typedef VarBindingsTy::iterator vb_iterator;
|
||||
vb_iterator vb_begin() const { return VarBindings.begin(); }
|
||||
vb_iterator vb_end() const { return VarBindings.end(); }
|
||||
|
||||
typedef ExprBindingsTy::iterator seb_iterator;
|
||||
seb_iterator seb_begin() const { return SubExprBindings.begin(); }
|
||||
seb_iterator seb_end() const { return SubExprBindings.end(); }
|
||||
|
||||
typedef ExprBindingsTy::iterator beb_iterator;
|
||||
beb_iterator beb_begin() const { return BlockExprBindings.begin(); }
|
||||
beb_iterator beb_end() const { return BlockExprBindings.end(); }
|
||||
|
||||
typedef ConstNotEqTy::iterator cne_iterator;
|
||||
cne_iterator cne_begin() const { return ConstNotEq.begin(); }
|
||||
cne_iterator cne_end() const { return ConstNotEq.end(); }
|
||||
|
||||
typedef ConstEqTy::iterator ce_iterator;
|
||||
ce_iterator ce_begin() const { return ConstEq.begin(); }
|
||||
ce_iterator ce_end() const { return ConstEq.end(); }
|
||||
|
||||
class CheckerStatePrinter {
|
||||
public:
|
||||
virtual ~CheckerStatePrinter() {}
|
||||
virtual void PrintCheckerState(std::ostream& Out, void* State,
|
||||
const char* nl, const char* sep) = 0;
|
||||
};
|
||||
|
||||
void print(std::ostream& Out, CheckerStatePrinter* P = NULL,
|
||||
const char* nl = "\n", const char* sep = "") const;
|
||||
|
||||
void printStdErr(CheckerStatePrinter* P = NULL) const;
|
||||
|
||||
void printDOT(std::ostream& Out, CheckerStatePrinter*P = NULL) const;
|
||||
};
|
||||
|
||||
template<> struct GRTrait<ValueState*> {
|
||||
static inline void* toPtr(ValueState* St) { return (void*) St; }
|
||||
static inline ValueState* toState(void* P) { return (ValueState*) P; }
|
||||
static inline void Profile(llvm::FoldingSetNodeID& profile, ValueState* St) {
|
||||
// At this point states have already been uniqued. Just
|
||||
// add the pointer.
|
||||
profile.AddPointer(St);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class ValueStateManager {
|
||||
private:
|
||||
ValueState::IntSetTy::Factory ISetFactory;
|
||||
ValueState::ExprBindingsTy::Factory EXFactory;
|
||||
ValueState::VarBindingsTy::Factory VBFactory;
|
||||
ValueState::ConstNotEqTy::Factory CNEFactory;
|
||||
ValueState::ConstEqTy::Factory CEFactory;
|
||||
|
||||
/// StateSet - FoldingSet containing all the states created for analyzing
|
||||
/// a particular function. This is used to unique states.
|
||||
llvm::FoldingSet<ValueState> 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;
|
||||
|
||||
private:
|
||||
|
||||
ValueState::ExprBindingsTy Remove(ValueState::ExprBindingsTy B, Expr* E) {
|
||||
return EXFactory.Remove(B, E);
|
||||
}
|
||||
|
||||
ValueState::VarBindingsTy Remove(ValueState::VarBindingsTy B, VarDecl* V) {
|
||||
return VBFactory.Remove(B, V);
|
||||
}
|
||||
|
||||
inline ValueState::ExprBindingsTy Remove(const ValueState& V, Expr* E) {
|
||||
return Remove(V.BlockExprBindings, E);
|
||||
}
|
||||
|
||||
inline ValueState::VarBindingsTy Remove(const ValueState& V, VarDecl* D) {
|
||||
return Remove(V.VarBindings, D);
|
||||
}
|
||||
|
||||
ValueState* BindVar(ValueState* St, VarDecl* D, RVal V);
|
||||
ValueState* UnbindVar(ValueState* St, VarDecl* D);
|
||||
|
||||
public:
|
||||
ValueStateManager(ASTContext& Ctx, llvm::BumpPtrAllocator& alloc)
|
||||
: ISetFactory(alloc),
|
||||
EXFactory(alloc),
|
||||
VBFactory(alloc),
|
||||
CNEFactory(alloc),
|
||||
CEFactory(alloc),
|
||||
BasicVals(Ctx, alloc),
|
||||
SymMgr(alloc),
|
||||
Alloc(alloc) {}
|
||||
|
||||
ValueState* getInitialState();
|
||||
|
||||
BasicValueFactory& getBasicValueFactory() { return BasicVals; }
|
||||
SymbolManager& getSymbolManager() { return SymMgr; }
|
||||
|
||||
typedef llvm::DenseSet<SymbolID> DeadSymbolsTy;
|
||||
|
||||
ValueState* RemoveDeadBindings(ValueState* St, Stmt* Loc,
|
||||
const LiveVariables& Liveness,
|
||||
DeadSymbolsTy& DeadSymbols);
|
||||
|
||||
ValueState* RemoveSubExprBindings(ValueState* St) {
|
||||
ValueState NewSt = *St;
|
||||
NewSt.SubExprBindings = EXFactory.GetEmptyMap();
|
||||
return getPersistentState(NewSt);
|
||||
}
|
||||
|
||||
ValueState* SetRVal(ValueState* St, Expr* E, RVal V, bool isBlkExpr,
|
||||
bool Invalidate);
|
||||
|
||||
ValueState* SetRVal(ValueState* St, LVal LV, RVal V);
|
||||
|
||||
RVal GetRVal(ValueState* St, Expr* E);
|
||||
RVal GetRVal(ValueState* St, LVal LV, QualType T = QualType());
|
||||
|
||||
RVal GetBlkExprRVal(ValueState* St, Expr* Ex);
|
||||
|
||||
void BindVar(ValueState& StImpl, VarDecl* D, RVal V);
|
||||
|
||||
void Unbind(ValueState& StImpl, LVal LV);
|
||||
|
||||
ValueState* getPersistentState(ValueState& Impl);
|
||||
|
||||
ValueState* AddEQ(ValueState* St, SymbolID sym, const llvm::APSInt& V);
|
||||
ValueState* AddNE(ValueState* St, SymbolID sym, const llvm::APSInt& V);
|
||||
};
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
#endif
|
||||
@@ -1,185 +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 { BlockEntranceKind=0, PostStmtKind=1, PostLoadKind=2,
|
||||
BlockExitKind=3, BlockEdgeSrcKind=4, BlockEdgeDstKind=5,
|
||||
BlockEdgeAuxKind=6 };
|
||||
protected:
|
||||
uintptr_t Data;
|
||||
|
||||
ProgramPoint(const void* Ptr, Kind k) {
|
||||
setRawData(Ptr, k);
|
||||
}
|
||||
|
||||
ProgramPoint() : Data(0) {}
|
||||
|
||||
void setRawData(const void* Ptr, Kind k) {
|
||||
assert ((reinterpret_cast<uintptr_t>(const_cast<void*>(Ptr)) & 0x7) == 0
|
||||
&& "Address must have at least an 8-byte alignment.");
|
||||
|
||||
Data = reinterpret_cast<uintptr_t>(const_cast<void*>(Ptr)) | k;
|
||||
}
|
||||
|
||||
public:
|
||||
unsigned getKind() const { return Data & 0x7; }
|
||||
void* getRawPtr() const { return reinterpret_cast<void*>(Data & ~0x7); }
|
||||
void* getRawData() const { return reinterpret_cast<void*>(Data); }
|
||||
|
||||
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; }
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID& ID) const {
|
||||
ID.AddInteger(getKind());
|
||||
ID.AddPointer(getRawPtr());
|
||||
}
|
||||
};
|
||||
|
||||
class BlockEntrance : public ProgramPoint {
|
||||
public:
|
||||
BlockEntrance(const CFGBlock* B) : ProgramPoint(B, BlockEntranceKind) {}
|
||||
|
||||
CFGBlock* getBlock() const {
|
||||
return reinterpret_cast<CFGBlock*>(getRawPtr());
|
||||
}
|
||||
|
||||
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*>(getRawPtr());
|
||||
}
|
||||
|
||||
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*) getRawPtr(); }
|
||||
|
||||
static bool classof(const ProgramPoint* Location) {
|
||||
unsigned k = Location->getKind();
|
||||
return k == PostStmtKind || k == PostLoadKind;
|
||||
}
|
||||
};
|
||||
|
||||
class PostLoad : public PostStmt {
|
||||
public:
|
||||
PostLoad(const Stmt* S) : PostStmt(S, PostLoadKind) {}
|
||||
|
||||
static bool classof(const ProgramPoint* Location) {
|
||||
return Location->getKind() == PostLoadKind;
|
||||
}
|
||||
};
|
||||
|
||||
class BlockEdge : public ProgramPoint {
|
||||
typedef std::pair<CFGBlock*,CFGBlock*> BPair;
|
||||
public:
|
||||
BlockEdge(CFG& cfg, const CFGBlock* B1, const CFGBlock* B2);
|
||||
|
||||
/// This ctor forces the BlockEdge to be constructed using an explicitly
|
||||
/// allocated pair object that is stored in the CFG. This is usually
|
||||
/// used to construct edges representing jumps using computed gotos.
|
||||
BlockEdge(CFG& cfg, const CFGBlock* B1, const CFGBlock* B2, bool)
|
||||
: ProgramPoint(cfg.getBlockEdgeImpl(B1, B2), BlockEdgeAuxKind) {}
|
||||
|
||||
|
||||
CFGBlock* getSrc() const;
|
||||
CFGBlock* getDst() const;
|
||||
|
||||
static bool classof(const ProgramPoint* Location) {
|
||||
unsigned k = Location->getKind();
|
||||
return k >= BlockEdgeSrcKind && k <= BlockEdgeAuxKind;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // 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 DenseMapInfo<void*>::getHashValue(Loc.getRawData());
|
||||
}
|
||||
|
||||
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:
|
||||
Idx(unsigned i) : I(i) {}
|
||||
explicit 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,88 +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 (ScopedDecl* D = DS->getDecl(); D != NULL; D = D->getNextDeclarator()) {
|
||||
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(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(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,198 +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 WarningsAsErrors; // Treat warnings like errors:
|
||||
bool WarnOnExtensions; // Enables warnings for gcc extensions: -pedantic.
|
||||
bool ErrorOnExtensions; // Error on extensions: -pedantic-errors.
|
||||
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);
|
||||
~Diagnostic();
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Diagnostic characterization methods, used by a client to customize how
|
||||
//
|
||||
|
||||
DiagnosticClient &getClient() { return Client; };
|
||||
|
||||
const DiagnosticClient &getClient() const { return Client; };
|
||||
|
||||
/// 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; }
|
||||
|
||||
/// 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 {
|
||||
public:
|
||||
virtual ~DiagnosticClient();
|
||||
|
||||
/// isInSystemHeader - If the client can tell that this is a system header,
|
||||
/// return true.
|
||||
virtual bool isInSystemHeader(FullSourceLoc Pos) const { return false; }
|
||||
|
||||
/// 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
|
||||
@@ -1,329 +0,0 @@
|
||||
//===--- IdentifierTable.h - Hash table for identifier lookup ---*- 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 IdentifierInfo, IdentifierTable, and Selector
|
||||
// interfaces.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_BASIC_IDENTIFIERTABLE_H
|
||||
#define LLVM_CLANG_BASIC_IDENTIFIERTABLE_H
|
||||
|
||||
#include "clang/Basic/TokenKinds.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/Bitcode/SerializationFwd.h"
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
|
||||
namespace llvm {
|
||||
template <typename T> struct DenseMapInfo;
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
struct LangOptions;
|
||||
class MultiKeywordSelector; // a private class used by Selector.
|
||||
|
||||
/// IdentifierInfo - One of these records is kept for each identifier that
|
||||
/// is lexed. This contains information about whether the token was #define'd,
|
||||
/// is a language keyword, or if it is a front-end token of some sort (e.g. a
|
||||
/// variable or function name). The preprocessor keeps this information in a
|
||||
/// set, and all tok::identifier tokens have a pointer to one of these.
|
||||
class IdentifierInfo {
|
||||
// Note: DON'T make TokenID a 'tok::TokenKind'; MSVC will treat it as a
|
||||
// signed char and TokenKinds > 127 won't be handled correctly.
|
||||
unsigned TokenID : 8; // Front-end token ID or tok::identifier.
|
||||
unsigned BuiltinID : 9; // ID if this is a builtin (__builtin_inf).
|
||||
// NOTE: VC++ treats enums as signed, avoid using tok::ObjCKeywordKind enum
|
||||
unsigned ObjCID : 5; // ID for objc @ keyword like @'protocol'.
|
||||
bool HasMacro : 1; // True if there is a #define for this.
|
||||
bool IsExtension : 1; // True if identifier is a lang extension.
|
||||
bool IsPoisoned : 1; // True if identifier is poisoned.
|
||||
bool IsCPPOperatorKeyword : 1; // True if ident is a C++ operator keyword.
|
||||
// 6 bits left in 32-bit word.
|
||||
void *FETokenInfo; // Managed by the language front-end.
|
||||
IdentifierInfo(const IdentifierInfo&); // NONCOPYABLE.
|
||||
void operator=(const IdentifierInfo&); // NONASSIGNABLE.
|
||||
public:
|
||||
IdentifierInfo();
|
||||
|
||||
/// getName - Return the actual string for this identifier. The returned
|
||||
/// string is properly null terminated.
|
||||
///
|
||||
const char *getName() const {
|
||||
// We know that this is embedded into a StringMapEntry, and it knows how to
|
||||
// efficiently find the string.
|
||||
return llvm::StringMapEntry<IdentifierInfo>::
|
||||
GetStringMapEntryFromValue(*this).getKeyData();
|
||||
}
|
||||
|
||||
/// getLength - Efficiently return the length of this identifier info.
|
||||
///
|
||||
unsigned getLength() const {
|
||||
return llvm::StringMapEntry<IdentifierInfo>::
|
||||
GetStringMapEntryFromValue(*this).getKeyLength();
|
||||
}
|
||||
|
||||
/// hasMacroDefinition - Return true if this identifier is #defined to some
|
||||
/// other value.
|
||||
bool hasMacroDefinition() const {
|
||||
return HasMacro;
|
||||
}
|
||||
void setHasMacroDefinition(bool Val) { HasMacro = Val; }
|
||||
|
||||
/// get/setTokenID - If this is a source-language token (e.g. 'for'), this API
|
||||
/// can be used to cause the lexer to map identifiers to source-language
|
||||
/// tokens.
|
||||
tok::TokenKind getTokenID() const { return (tok::TokenKind)TokenID; }
|
||||
void setTokenID(tok::TokenKind ID) { TokenID = ID; }
|
||||
|
||||
/// getPPKeywordID - Return the preprocessor keyword ID for this identifier.
|
||||
/// For example, "define" will return tok::pp_define.
|
||||
tok::PPKeywordKind getPPKeywordID() const;
|
||||
|
||||
/// getObjCKeywordID - Return the Objective-C keyword ID for the this
|
||||
/// identifier. For example, 'class' will return tok::objc_class if ObjC is
|
||||
/// enabled.
|
||||
tok::ObjCKeywordKind getObjCKeywordID() const {
|
||||
return tok::ObjCKeywordKind(ObjCID);
|
||||
}
|
||||
void setObjCKeywordID(tok::ObjCKeywordKind ID) { ObjCID = ID; }
|
||||
|
||||
/// getBuiltinID - Return a value indicating whether this is a builtin
|
||||
/// function. 0 is not-built-in. 1 is builtin-for-some-nonprimary-target.
|
||||
/// 2+ are specific builtin functions.
|
||||
unsigned getBuiltinID() const { return BuiltinID; }
|
||||
void setBuiltinID(unsigned ID) {
|
||||
BuiltinID = ID;
|
||||
assert(BuiltinID == ID && "ID too large for field!");
|
||||
}
|
||||
|
||||
/// get/setExtension - Initialize information about whether or not this
|
||||
/// language token is an extension. This controls extension warnings, and is
|
||||
/// only valid if a custom token ID is set.
|
||||
bool isExtensionToken() const { return IsExtension; }
|
||||
void setIsExtensionToken(bool Val) { IsExtension = Val; }
|
||||
|
||||
/// setIsPoisoned - Mark this identifier as poisoned. After poisoning, the
|
||||
/// Preprocessor will emit an error every time this token is used.
|
||||
void setIsPoisoned(bool Value = true) { IsPoisoned = Value; }
|
||||
|
||||
/// isPoisoned - Return true if this token has been poisoned.
|
||||
bool isPoisoned() const { return IsPoisoned; }
|
||||
|
||||
/// isCPlusPlusOperatorKeyword/setIsCPlusPlusOperatorKeyword controls whether
|
||||
/// this identifier is a C++ alternate representation of an operator.
|
||||
void setIsCPlusPlusOperatorKeyword(bool Val = true)
|
||||
{ IsCPPOperatorKeyword = Val; }
|
||||
bool isCPlusPlusOperatorKeyword() const { return IsCPPOperatorKeyword; }
|
||||
|
||||
/// getFETokenInfo/setFETokenInfo - The language front-end is allowed to
|
||||
/// associate arbitrary metadata with this token.
|
||||
template<typename T>
|
||||
T *getFETokenInfo() const { return static_cast<T*>(FETokenInfo); }
|
||||
void setFETokenInfo(void *T) { FETokenInfo = T; }
|
||||
|
||||
/// Emit - Serialize this IdentifierInfo to a bitstream.
|
||||
void Emit(llvm::Serializer& S) const;
|
||||
|
||||
/// Read - Deserialize an IdentifierInfo object from a bitstream.
|
||||
void Read(llvm::Deserializer& D);
|
||||
};
|
||||
|
||||
/// IdentifierTable - This table implements an efficient mapping from strings to
|
||||
/// IdentifierInfo nodes. It has no other purpose, but this is an
|
||||
/// extremely performance-critical piece of the code, as each occurrance of
|
||||
/// every identifier goes through here when lexed.
|
||||
class IdentifierTable {
|
||||
// Shark shows that using MallocAllocator is *much* slower than using this
|
||||
// BumpPtrAllocator!
|
||||
typedef llvm::StringMap<IdentifierInfo, llvm::BumpPtrAllocator> HashTableTy;
|
||||
HashTableTy HashTable;
|
||||
public:
|
||||
/// IdentifierTable ctor - Create the identifier table, populating it with
|
||||
/// info about the language keywords for the language specified by LangOpts.
|
||||
IdentifierTable(const LangOptions &LangOpts);
|
||||
|
||||
/// get - Return the identifier token info for the specified named identifier.
|
||||
///
|
||||
IdentifierInfo &get(const char *NameStart, const char *NameEnd) {
|
||||
return HashTable.GetOrCreateValue(NameStart, NameEnd).getValue();
|
||||
}
|
||||
|
||||
IdentifierInfo &get(const char *Name) {
|
||||
return get(Name, Name+strlen(Name));
|
||||
}
|
||||
IdentifierInfo &get(const std::string &Name) {
|
||||
// Don't use c_str() here: no need to be null terminated.
|
||||
const char *NameBytes = &Name[0];
|
||||
return get(NameBytes, NameBytes+Name.size());
|
||||
}
|
||||
|
||||
typedef HashTableTy::const_iterator iterator;
|
||||
typedef HashTableTy::const_iterator const_iterator;
|
||||
|
||||
iterator begin() const { return HashTable.begin(); }
|
||||
iterator end() const { return HashTable.end(); }
|
||||
|
||||
unsigned size() const { return HashTable.size(); }
|
||||
|
||||
/// PrintStats - Print some statistics to stderr that indicate how well the
|
||||
/// hashing is doing.
|
||||
void PrintStats() const;
|
||||
|
||||
void AddKeywords(const LangOptions &LangOpts);
|
||||
|
||||
/// Emit - Serialize this IdentifierTable to a bitstream. This should
|
||||
/// be called AFTER objects that externally reference the identifiers in the
|
||||
/// table have been serialized. This is because only the identifiers that
|
||||
/// are actually referenced are serialized.
|
||||
void Emit(llvm::Serializer& S) const;
|
||||
|
||||
/// Create - Deserialize an IdentifierTable from a bitstream.
|
||||
static IdentifierTable* CreateAndRegister(llvm::Deserializer& D);
|
||||
|
||||
private:
|
||||
/// This ctor is not intended to be used by anyone except for object
|
||||
/// serialization.
|
||||
IdentifierTable();
|
||||
};
|
||||
|
||||
/// Selector - This smart pointer class efficiently represents Objective-C
|
||||
/// method names. This class will either point to an IdentifierInfo or a
|
||||
/// MultiKeywordSelector (which is private). This enables us to optimize
|
||||
/// selectors that no arguments and selectors that take 1 argument, which
|
||||
/// accounts for 78% of all selectors in Cocoa.h.
|
||||
class Selector {
|
||||
enum IdentifierInfoFlag {
|
||||
// MultiKeywordSelector = 0.
|
||||
ZeroArg = 0x1,
|
||||
OneArg = 0x2,
|
||||
ArgFlags = ZeroArg|OneArg
|
||||
};
|
||||
uintptr_t InfoPtr; // a pointer to the MultiKeywordSelector or IdentifierInfo.
|
||||
|
||||
Selector(IdentifierInfo *II, unsigned nArgs) {
|
||||
InfoPtr = reinterpret_cast<uintptr_t>(II);
|
||||
assert((InfoPtr & ArgFlags) == 0 &&"Insufficiently aligned IdentifierInfo");
|
||||
assert(nArgs < 2 && "nArgs not equal to 0/1");
|
||||
InfoPtr |= nArgs+1;
|
||||
}
|
||||
Selector(MultiKeywordSelector *SI) {
|
||||
InfoPtr = reinterpret_cast<uintptr_t>(SI);
|
||||
assert((InfoPtr & ArgFlags) == 0 &&"Insufficiently aligned IdentifierInfo");
|
||||
}
|
||||
Selector(uintptr_t V) : InfoPtr(V) {}
|
||||
public:
|
||||
friend class SelectorTable; // only the SelectorTable can create these.
|
||||
|
||||
/// The default ctor should only be used when creating data structures that
|
||||
/// will contain selectors.
|
||||
Selector() : InfoPtr(0) {}
|
||||
|
||||
IdentifierInfo *getAsIdentifierInfo() const {
|
||||
if (getIdentifierInfoFlag())
|
||||
return reinterpret_cast<IdentifierInfo *>(InfoPtr & ~ArgFlags);
|
||||
return 0;
|
||||
}
|
||||
unsigned getIdentifierInfoFlag() const {
|
||||
return InfoPtr & ArgFlags;
|
||||
}
|
||||
/// operator==/!= - Indicate whether the specified selectors are identical.
|
||||
bool operator==(Selector RHS) const {
|
||||
return InfoPtr == RHS.InfoPtr;
|
||||
}
|
||||
bool operator!=(Selector RHS) const {
|
||||
return InfoPtr != RHS.InfoPtr;
|
||||
}
|
||||
void *getAsOpaquePtr() const {
|
||||
return reinterpret_cast<void*>(InfoPtr);
|
||||
}
|
||||
// Predicates to identify the selector type.
|
||||
bool isKeywordSelector() const {
|
||||
return getIdentifierInfoFlag() != ZeroArg;
|
||||
}
|
||||
bool isUnarySelector() const {
|
||||
return getIdentifierInfoFlag() == ZeroArg;
|
||||
}
|
||||
unsigned getNumArgs() const;
|
||||
IdentifierInfo *getIdentifierInfoForSlot(unsigned argIndex) const;
|
||||
|
||||
/// getName - Derive the full selector name (e.g. "foo:bar:") and return it.
|
||||
///
|
||||
std::string getName() const;
|
||||
|
||||
static Selector getEmptyMarker() {
|
||||
return Selector(uintptr_t(-1));
|
||||
}
|
||||
static Selector getTombstoneMarker() {
|
||||
return Selector(uintptr_t(-2));
|
||||
}
|
||||
|
||||
// Emit - Emit a selector to bitcode.
|
||||
void Emit(llvm::Serializer& S) const;
|
||||
|
||||
// ReadVal - Read a selector from bitcode.
|
||||
static Selector ReadVal(llvm::Deserializer& D);
|
||||
};
|
||||
|
||||
/// SelectorTable - This table allows us to fully hide how we implement
|
||||
/// multi-keyword caching.
|
||||
class SelectorTable {
|
||||
void *Impl; // Actually a FoldingSet<MultiKeywordSelector>*
|
||||
SelectorTable(const SelectorTable&); // DISABLED: DO NOT IMPLEMENT
|
||||
void operator=(const SelectorTable&); // DISABLED: DO NOT IMPLEMENT
|
||||
public:
|
||||
SelectorTable();
|
||||
~SelectorTable();
|
||||
|
||||
/// getSelector - This can create any sort of selector. NumArgs indicates
|
||||
/// whether this is a no argument selector "foo", a single argument selector
|
||||
/// "foo:" or multi-argument "foo:bar:".
|
||||
Selector getSelector(unsigned NumArgs, IdentifierInfo **IIV);
|
||||
|
||||
Selector getUnarySelector(IdentifierInfo *ID) {
|
||||
return Selector(ID, 1);
|
||||
}
|
||||
Selector getNullarySelector(IdentifierInfo *ID) {
|
||||
return Selector(ID, 0);
|
||||
}
|
||||
|
||||
// Emit - Emit a SelectorTable to bitcode.
|
||||
void Emit(llvm::Serializer& S) const;
|
||||
|
||||
// Create - Reconstitute a SelectorTable from bitcode.
|
||||
static SelectorTable* CreateAndRegister(llvm::Deserializer& D);
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
|
||||
/// Define DenseMapInfo so that Selectors can be used as keys in DenseMap and
|
||||
/// DenseSets.
|
||||
namespace llvm {
|
||||
template <>
|
||||
struct DenseMapInfo<clang::Selector> {
|
||||
static inline clang::Selector getEmptyKey() {
|
||||
return clang::Selector::getEmptyMarker();
|
||||
}
|
||||
static inline clang::Selector getTombstoneKey() {
|
||||
return clang::Selector::getTombstoneMarker();
|
||||
}
|
||||
|
||||
static unsigned getHashValue(clang::Selector S);
|
||||
|
||||
static bool isEqual(clang::Selector LHS, clang::Selector RHS) {
|
||||
return LHS == RHS;
|
||||
}
|
||||
|
||||
static bool isPod() { return true; }
|
||||
};
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
||||
@@ -1,75 +0,0 @@
|
||||
//===--- LangOptions.h - C Language Family Language Options -----*- 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 LangOptions interface.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_LANGOPTIONS_H
|
||||
#define LLVM_CLANG_LANGOPTIONS_H
|
||||
|
||||
#include "llvm/Bitcode/SerializationFwd.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
/// LangOptions - This class keeps track of the various options that can be
|
||||
/// enabled, which controls the dialect of C that is accepted.
|
||||
struct LangOptions {
|
||||
|
||||
unsigned Trigraphs : 1; // Trigraphs in source files.
|
||||
unsigned BCPLComment : 1; // BCPL-style '//' comments.
|
||||
unsigned DollarIdents : 1; // '$' allowed in identifiers.
|
||||
unsigned ImplicitInt : 1; // C89 implicit 'int'.
|
||||
unsigned Digraphs : 1; // C94, C99 and C++
|
||||
unsigned HexFloats : 1; // C99 Hexadecimal float constants.
|
||||
unsigned C99 : 1; // C99 Support
|
||||
unsigned Microsoft : 1; // Microsoft extensions.
|
||||
unsigned CPlusPlus : 1; // C++ Support
|
||||
unsigned CPlusPlus0x : 1; // C++0x Support
|
||||
unsigned NoExtensions : 1; // All extensions are disabled, strict mode.
|
||||
unsigned CXXOperatorNames : 1; // Treat C++ operator names as keywords.
|
||||
|
||||
unsigned ObjC1 : 1; // Objective-C 1 support enabled.
|
||||
unsigned ObjC2 : 1; // Objective-C 2 support enabled.
|
||||
|
||||
unsigned PascalStrings : 1; // Allow Pascal strings
|
||||
unsigned Boolean : 1; // Allow bool/true/false
|
||||
unsigned WritableStrings : 1; // Allow writable strings
|
||||
unsigned LaxVectorConversions : 1;
|
||||
|
||||
private:
|
||||
unsigned GC : 2; // Objective-C Garbage Collection modes. We declare
|
||||
// this enum as unsigned because MSVC insists on making enums
|
||||
// signed. Set/Query this value using accessors.
|
||||
public:
|
||||
|
||||
enum GCMode { NonGC, GCOnly, HybridGC };
|
||||
|
||||
LangOptions() {
|
||||
Trigraphs = BCPLComment = DollarIdents = ImplicitInt = Digraphs = 0;
|
||||
HexFloats = 0;
|
||||
GC = ObjC1 = ObjC2 = 0;
|
||||
C99 = Microsoft = CPlusPlus = CPlusPlus0x = NoExtensions = 0;
|
||||
CXXOperatorNames = PascalStrings = Boolean = WritableStrings = 0;
|
||||
LaxVectorConversions = 0;
|
||||
}
|
||||
|
||||
GCMode getGCMode() const { return (GCMode) GC; }
|
||||
void setGCMode(GCMode m) { GC = (unsigned) m; }
|
||||
|
||||
/// Emit - Emit this LangOptions object to bitcode.
|
||||
void Emit(llvm::Serializer& S) const;
|
||||
|
||||
/// Read - Read new values for this LangOption object from bitcode.
|
||||
void Read(llvm::Deserializer& S);
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
@@ -1,265 +0,0 @@
|
||||
//===--- SourceLocation.h - Compact identifier for Source Files -*- 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 SourceLocation class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_SOURCELOCATION_H
|
||||
#define LLVM_CLANG_SOURCELOCATION_H
|
||||
|
||||
#include <cassert>
|
||||
#include "llvm/Bitcode/SerializationFwd.h"
|
||||
|
||||
namespace llvm {
|
||||
class MemoryBuffer;
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
|
||||
class SourceManager;
|
||||
class FileEntry;
|
||||
|
||||
/// SourceLocation - This is a carefully crafted 32-bit identifier that encodes
|
||||
/// a full include stack, line and column number information for a position in
|
||||
/// an input translation unit.
|
||||
class SourceLocation {
|
||||
unsigned ID;
|
||||
public:
|
||||
enum {
|
||||
// FileID Layout:
|
||||
// bit 31: 0 -> FileID, 1 -> MacroID (invalid for FileID)
|
||||
// 30...17 -> FileID of source location, index into SourceManager table.
|
||||
FileIDBits = 14,
|
||||
// 0...16 -> Index into the chunk of the specified FileID.
|
||||
FilePosBits = 32-1-FileIDBits,
|
||||
|
||||
// MacroID Layout:
|
||||
// bit 31: 1 -> MacroID, 0 -> FileID (invalid for MacroID)
|
||||
|
||||
// bit 29,30: unused.
|
||||
|
||||
// bits 28...9 -> MacroID number.
|
||||
MacroIDBits = 20,
|
||||
// bits 8...0 -> Macro Physical offset
|
||||
MacroPhysOffsBits = 9,
|
||||
|
||||
|
||||
// Useful constants.
|
||||
ChunkSize = (1 << FilePosBits)
|
||||
};
|
||||
|
||||
SourceLocation() : ID(0) {} // 0 is an invalid FileID.
|
||||
|
||||
bool isFileID() const { return (ID >> 31) == 0; }
|
||||
bool isMacroID() const { return (ID >> 31) != 0; }
|
||||
|
||||
/// isValid - Return true if this is a valid SourceLocation object. Invalid
|
||||
/// SourceLocations are often used when events have no corresponding location
|
||||
/// in the source (e.g. a diagnostic is required for a command line option).
|
||||
///
|
||||
bool isValid() const { return ID != 0; }
|
||||
bool isInvalid() const { return ID == 0; }
|
||||
|
||||
static SourceLocation getFileLoc(unsigned FileID, unsigned FilePos) {
|
||||
SourceLocation L;
|
||||
// If a FilePos is larger than (1<<FilePosBits), the SourceManager makes
|
||||
// enough consequtive FileIDs that we have one for each chunk.
|
||||
if (FilePos >= ChunkSize) {
|
||||
FileID += FilePos >> FilePosBits;
|
||||
FilePos &= ChunkSize-1;
|
||||
}
|
||||
|
||||
// FIXME: Find a way to handle out of FileID bits! Maybe MaxFileID is an
|
||||
// escape of some sort?
|
||||
assert(FileID < (1 << FileIDBits) && "Out of fileid's");
|
||||
|
||||
L.ID = (FileID << FilePosBits) | FilePos;
|
||||
return L;
|
||||
}
|
||||
|
||||
static bool isValidMacroPhysOffs(int Val) {
|
||||
if (Val >= 0)
|
||||
return Val < (1 << (MacroPhysOffsBits-1));
|
||||
return -Val < (1 << (MacroPhysOffsBits-1));
|
||||
}
|
||||
|
||||
static SourceLocation getMacroLoc(unsigned MacroID, int PhysOffs){
|
||||
assert(MacroID < (1 << MacroIDBits) && "Too many macros!");
|
||||
assert(isValidMacroPhysOffs(PhysOffs) && "Physoffs too large!");
|
||||
|
||||
// Mask off sign bits.
|
||||
PhysOffs &= (1 << MacroPhysOffsBits)-1;
|
||||
|
||||
SourceLocation L;
|
||||
L.ID = (1 << 31) |
|
||||
(MacroID << MacroPhysOffsBits) |
|
||||
PhysOffs;
|
||||
return L;
|
||||
}
|
||||
|
||||
|
||||
/// getFileID - Return the file identifier for this SourceLocation. This
|
||||
/// FileID can be used with the SourceManager object to obtain an entire
|
||||
/// include stack for a file position reference.
|
||||
unsigned getFileID() const {
|
||||
assert(isFileID() && "can't get the file id of a non-file sloc!");
|
||||
return ID >> FilePosBits;
|
||||
}
|
||||
|
||||
/// getRawFilePos - Return the byte offset from the start of the file-chunk
|
||||
/// referred to by FileID. This method should not be used to get the offset
|
||||
/// from the start of the file, instead you should use
|
||||
/// SourceManager::getDecomposedFileLoc. This method will be
|
||||
// incorrect for large files.
|
||||
unsigned getRawFilePos() const {
|
||||
assert(isFileID() && "can't get the file id of a non-file sloc!");
|
||||
return ID & (ChunkSize-1);
|
||||
}
|
||||
|
||||
unsigned getMacroID() const {
|
||||
assert(isMacroID() && "Is not a macro id!");
|
||||
return (ID >> MacroPhysOffsBits) & ((1 << MacroIDBits)-1);
|
||||
}
|
||||
|
||||
int getMacroPhysOffs() const {
|
||||
assert(isMacroID() && "Is not a macro id!");
|
||||
int Val = ID & ((1 << MacroPhysOffsBits)-1);
|
||||
// Sign extend it properly.
|
||||
unsigned ShAmt = sizeof(int)*8 - MacroPhysOffsBits;
|
||||
return (Val << ShAmt) >> ShAmt;
|
||||
}
|
||||
|
||||
/// getFileLocWithOffset - Return a source location with the specified offset
|
||||
/// from this file SourceLocation.
|
||||
SourceLocation getFileLocWithOffset(int Offset) const {
|
||||
unsigned FileID = getFileID();
|
||||
Offset += getRawFilePos();
|
||||
// Handle negative offsets correctly.
|
||||
while (Offset < 0) {
|
||||
--FileID;
|
||||
Offset += ChunkSize;
|
||||
}
|
||||
return getFileLoc(FileID, Offset);
|
||||
}
|
||||
|
||||
/// getRawEncoding - When a SourceLocation itself cannot be used, this returns
|
||||
/// an (opaque) 32-bit integer encoding for it. This should only be passed
|
||||
/// to SourceLocation::getFromRawEncoding, it should not be inspected
|
||||
/// directly.
|
||||
unsigned getRawEncoding() const { return ID; }
|
||||
|
||||
/// getFromRawEncoding - Turn a raw encoding of a SourceLocation object into
|
||||
/// a real SourceLocation.
|
||||
static SourceLocation getFromRawEncoding(unsigned Encoding) {
|
||||
SourceLocation X;
|
||||
X.ID = Encoding;
|
||||
return X;
|
||||
}
|
||||
|
||||
/// Emit - Emit this SourceLocation object to Bitcode.
|
||||
void Emit(llvm::Serializer& S) const;
|
||||
|
||||
/// ReadVal - Read a SourceLocation object from Bitcode.
|
||||
static SourceLocation ReadVal(llvm::Deserializer& D);
|
||||
};
|
||||
|
||||
inline bool operator==(const SourceLocation &LHS, const SourceLocation &RHS) {
|
||||
return LHS.getRawEncoding() == RHS.getRawEncoding();
|
||||
}
|
||||
|
||||
inline bool operator!=(const SourceLocation &LHS, const SourceLocation &RHS) {
|
||||
return !(LHS == RHS);
|
||||
}
|
||||
|
||||
/// SourceRange - a trival tuple used to represent a source range.
|
||||
class SourceRange {
|
||||
SourceLocation B;
|
||||
SourceLocation E;
|
||||
public:
|
||||
SourceRange(): B(SourceLocation()), E(SourceLocation()) {}
|
||||
SourceRange(SourceLocation loc) : B(loc), E(loc) {}
|
||||
SourceRange(SourceLocation begin, SourceLocation end) : B(begin), E(end) {}
|
||||
|
||||
SourceLocation getBegin() const { return B; }
|
||||
SourceLocation getEnd() const { return E; }
|
||||
|
||||
void setBegin(SourceLocation b) { B = b; }
|
||||
void setEnd(SourceLocation e) { E = e; }
|
||||
|
||||
bool isValid() const { return B.isValid() && E.isValid(); }
|
||||
|
||||
/// Emit - Emit this SourceRange object to Bitcode.
|
||||
void Emit(llvm::Serializer& S) const;
|
||||
|
||||
/// ReadVal - Read a SourceRange object from Bitcode.
|
||||
static SourceRange ReadVal(llvm::Deserializer& D);
|
||||
};
|
||||
|
||||
/// FullSourceLoc - A tuple containing both a SourceLocation
|
||||
/// and its associated SourceManager. Useful for argument passing to functions
|
||||
/// that expect both objects.
|
||||
class FullSourceLoc {
|
||||
SourceLocation Loc;
|
||||
SourceManager* SrcMgr;
|
||||
public:
|
||||
// Creates a FullSourceLoc where isValid() returns false.
|
||||
explicit FullSourceLoc()
|
||||
: Loc(SourceLocation()), SrcMgr((SourceManager*) 0) {}
|
||||
|
||||
explicit FullSourceLoc(SourceLocation loc, SourceManager& smgr)
|
||||
: Loc(loc), SrcMgr(&smgr) {}
|
||||
|
||||
bool isValid() const { return Loc.isValid(); }
|
||||
bool isInvalid() const { return Loc.isInvalid(); }
|
||||
|
||||
SourceLocation getLocation() const { return Loc; }
|
||||
|
||||
SourceManager& getManager() {
|
||||
assert (SrcMgr && "SourceManager is NULL.");
|
||||
return *SrcMgr;
|
||||
}
|
||||
|
||||
const SourceManager& getManager() const {
|
||||
assert (SrcMgr && "SourceManager is NULL.");
|
||||
return *SrcMgr;
|
||||
}
|
||||
|
||||
FullSourceLoc getLogicalLoc();
|
||||
FullSourceLoc getIncludeLoc();
|
||||
|
||||
unsigned getLineNumber() const;
|
||||
unsigned getColumnNumber() const;
|
||||
|
||||
unsigned getLogicalLineNumber() const;
|
||||
unsigned getLogicalColumnNumber() const;
|
||||
|
||||
const char *getCharacterData() const;
|
||||
|
||||
const llvm::MemoryBuffer* getBuffer() const;
|
||||
|
||||
const char* getSourceName() const;
|
||||
const FileEntry* getFileEntryForLoc() const;
|
||||
|
||||
bool isFileID() const { return Loc.isFileID(); }
|
||||
|
||||
unsigned getCanonicalFileID() const;
|
||||
|
||||
bool operator==(const FullSourceLoc& RHS) const {
|
||||
return SrcMgr == RHS.SrcMgr && Loc == RHS.Loc;
|
||||
}
|
||||
|
||||
bool operator!=(const FullSourceLoc& RHS) const {
|
||||
return SrcMgr != RHS.SrcMgr || Loc != RHS.Loc;
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
@@ -1,471 +0,0 @@
|
||||
//===--- SourceManager.h - Track and cache source files ---------*- 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 SourceManager interface.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_SOURCEMANAGER_H
|
||||
#define LLVM_CLANG_SOURCEMANAGER_H
|
||||
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "llvm/Bitcode/SerializationFwd.h"
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <list>
|
||||
#include <cassert>
|
||||
|
||||
namespace llvm {
|
||||
class MemoryBuffer;
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
|
||||
class SourceManager;
|
||||
class FileManager;
|
||||
class FileEntry;
|
||||
class IdentifierTokenInfo;
|
||||
|
||||
/// SrcMgr - Private classes that are part of the SourceManager implementation.
|
||||
///
|
||||
namespace SrcMgr {
|
||||
/// ContentCache - Once instance of this struct is kept for every file
|
||||
/// loaded or used. This object owns the MemoryBuffer object.
|
||||
struct ContentCache {
|
||||
/// Reference to the file entry. This reference does not own
|
||||
/// the FileEntry object. It is possible for this to be NULL if
|
||||
/// the ContentCache encapsulates an imaginary text buffer.
|
||||
const FileEntry* Entry;
|
||||
|
||||
/// Buffer - The actual buffer containing the characters from the input
|
||||
/// file. This is owned by the ContentCache object.
|
||||
const llvm::MemoryBuffer* Buffer;
|
||||
|
||||
/// SourceLineCache - A new[]'d array of offsets for each source line. This
|
||||
/// is lazily computed. This is owned by the ContentCache object.
|
||||
unsigned* SourceLineCache;
|
||||
|
||||
/// NumLines - The number of lines in this ContentCache. This is only valid
|
||||
/// if SourceLineCache is non-null.
|
||||
unsigned NumLines;
|
||||
|
||||
ContentCache(const FileEntry* e = NULL)
|
||||
: Entry(e), Buffer(NULL), SourceLineCache(NULL), NumLines(0) {}
|
||||
|
||||
~ContentCache();
|
||||
|
||||
/// The copy ctor does not allow copies where source object has either
|
||||
/// a non-NULL Buffer or SourceLineCache. Ownership of allocated memory
|
||||
/// is not transfered, so this is a logical error.
|
||||
ContentCache(const ContentCache& RHS) : Buffer(NULL),SourceLineCache(NULL) {
|
||||
Entry = RHS.Entry;
|
||||
|
||||
assert (RHS.Buffer == NULL && RHS.SourceLineCache == NULL
|
||||
&& "Passed ContentCache object cannot own a buffer.");
|
||||
|
||||
NumLines = RHS.NumLines;
|
||||
}
|
||||
|
||||
/// Emit - Emit this ContentCache to Bitcode.
|
||||
void Emit(llvm::Serializer& S) const;
|
||||
|
||||
/// ReadToSourceManager - Reconstitute a ContentCache from Bitcode
|
||||
// and store it in the specified SourceManager.
|
||||
static void ReadToSourceManager(llvm::Deserializer& D, SourceManager& SMgr,
|
||||
FileManager* FMgr, std::vector<char>& Buf);
|
||||
|
||||
private:
|
||||
// Disable assignments.
|
||||
ContentCache& operator=(const ContentCache& RHS);
|
||||
};
|
||||
|
||||
/// FileIDInfo - Information about a FileID, basically just the logical file
|
||||
/// that it represents and include stack information. A File SourceLocation
|
||||
/// is a byte offset from the start of this.
|
||||
///
|
||||
/// FileID's are used to compute the location of a character in memory as well
|
||||
/// as the logical source location, which can be differ from the physical
|
||||
/// location. It is different when #line's are active or when macros have
|
||||
/// been expanded.
|
||||
///
|
||||
/// Each FileID has include stack information, indicating where it came from.
|
||||
/// For the primary translation unit, it comes from SourceLocation() aka 0.
|
||||
/// This information encodes the #include chain that a token was instantiated
|
||||
/// from.
|
||||
///
|
||||
/// FileIDInfos contain a "ContentCache *", describing the source file,
|
||||
/// and a Chunk number, which allows a SourceLocation to index into very
|
||||
/// large files (those which there are not enough FilePosBits to address).
|
||||
///
|
||||
struct FileIDInfo {
|
||||
private:
|
||||
/// IncludeLoc - The location of the #include that brought in this file.
|
||||
/// This SourceLocation object has an invalid SLOC for the main file.
|
||||
SourceLocation IncludeLoc;
|
||||
|
||||
/// ChunkNo - Really large buffers are broken up into chunks that are
|
||||
/// each (1 << SourceLocation::FilePosBits) in size. This specifies the
|
||||
/// chunk number of this FileID.
|
||||
unsigned ChunkNo;
|
||||
|
||||
/// Content - Information about the source buffer itself.
|
||||
const ContentCache* Content;
|
||||
|
||||
public:
|
||||
/// get - Return a FileIDInfo object.
|
||||
static FileIDInfo get(SourceLocation IL, unsigned CN,
|
||||
const ContentCache *Con) {
|
||||
FileIDInfo X;
|
||||
X.IncludeLoc = IL;
|
||||
X.ChunkNo = CN;
|
||||
X.Content = Con;
|
||||
return X;
|
||||
}
|
||||
|
||||
SourceLocation getIncludeLoc() const { return IncludeLoc; }
|
||||
unsigned getChunkNo() const { return ChunkNo; }
|
||||
const ContentCache* getContentCache() const { return Content; }
|
||||
|
||||
/// Emit - Emit this FileIDInfo to Bitcode.
|
||||
void Emit(llvm::Serializer& S) const;
|
||||
|
||||
/// ReadVal - Reconstitute a FileIDInfo from Bitcode.
|
||||
static FileIDInfo ReadVal(llvm::Deserializer& S);
|
||||
};
|
||||
|
||||
/// MacroIDInfo - Macro SourceLocations refer to these records by their ID.
|
||||
/// Each MacroIDInfo encodes the Instantiation location - where the macro was
|
||||
/// instantiated, and the PhysicalLoc - where the actual character data for
|
||||
/// the token came from. An actual macro SourceLocation stores deltas from
|
||||
/// these positions.
|
||||
class MacroIDInfo {
|
||||
SourceLocation VirtualLoc, PhysicalLoc;
|
||||
public:
|
||||
SourceLocation getVirtualLoc() const { return VirtualLoc; }
|
||||
SourceLocation getPhysicalLoc() const { return PhysicalLoc; }
|
||||
|
||||
/// get - Return a MacroID for a macro expansion. VL specifies
|
||||
/// the instantiation location (where the macro is expanded), and PL
|
||||
/// specifies the physical location (where the characters from the token
|
||||
/// come from). Both VL and PL refer to normal File SLocs.
|
||||
static MacroIDInfo get(SourceLocation VL, SourceLocation PL) {
|
||||
MacroIDInfo X;
|
||||
X.VirtualLoc = VL;
|
||||
X.PhysicalLoc = PL;
|
||||
return X;
|
||||
}
|
||||
|
||||
/// Emit - Emit this MacroIDInfo to Bitcode.
|
||||
void Emit(llvm::Serializer& S) const;
|
||||
|
||||
/// ReadVal - Reconstitute a MacroIDInfo from Bitcode.
|
||||
static MacroIDInfo ReadVal(llvm::Deserializer& S);
|
||||
};
|
||||
} // end SrcMgr namespace.
|
||||
} // end clang namespace
|
||||
|
||||
namespace std {
|
||||
template <> struct less<clang::SrcMgr::ContentCache> {
|
||||
inline bool operator()(const clang::SrcMgr::ContentCache& L,
|
||||
const clang::SrcMgr::ContentCache& R) const {
|
||||
return L.Entry < R.Entry;
|
||||
}
|
||||
};
|
||||
} // end std namespace
|
||||
|
||||
namespace clang {
|
||||
|
||||
/// SourceManager - This file handles loading and caching of source files into
|
||||
/// memory. This object owns the MemoryBuffer objects for all of the loaded
|
||||
/// files and assigns unique FileID's for each unique #include chain.
|
||||
///
|
||||
/// The SourceManager can be queried for information about SourceLocation
|
||||
/// objects, turning them into either physical or logical locations. Physical
|
||||
/// locations represent where the bytes corresponding to a token came from and
|
||||
/// logical locations represent where the location is in the user's view. In
|
||||
/// the case of a macro expansion, for example, the physical location indicates
|
||||
/// where the expanded token came from and the logical location specifies where
|
||||
/// it was expanded. Logical locations are also influenced by #line directives,
|
||||
/// etc.
|
||||
class SourceManager {
|
||||
/// FileInfos - Memoized information about all of the files tracked by this
|
||||
/// SourceManager. This set allows us to merge ContentCache entries based
|
||||
/// on their FileEntry*. All ContentCache objects will thus have unique,
|
||||
/// non-null, FileEntry pointers.
|
||||
std::set<SrcMgr::ContentCache> FileInfos;
|
||||
|
||||
/// MemBufferInfos - Information about various memory buffers that we have
|
||||
/// read in. This is a list, instead of a vector, because we need pointers to
|
||||
/// the ContentCache objects to be stable. All FileEntry* within the
|
||||
/// stored ContentCache objects are NULL, as they do not refer to a file.
|
||||
std::list<SrcMgr::ContentCache> MemBufferInfos;
|
||||
|
||||
/// FileIDs - Information about each FileID. FileID #0 is not valid, so all
|
||||
/// entries are off by one.
|
||||
std::vector<SrcMgr::FileIDInfo> FileIDs;
|
||||
|
||||
/// MacroIDs - Information about each MacroID.
|
||||
std::vector<SrcMgr::MacroIDInfo> MacroIDs;
|
||||
|
||||
/// LastLineNo - These ivars serve as a cache used in the getLineNumber
|
||||
/// method which is used to speedup getLineNumber calls to nearby locations.
|
||||
unsigned LastLineNoFileIDQuery;
|
||||
SrcMgr::ContentCache *LastLineNoContentCache;
|
||||
unsigned LastLineNoFilePos;
|
||||
unsigned LastLineNoResult;
|
||||
|
||||
/// MainFileID - The file ID for the main source file of the translation unit.
|
||||
unsigned MainFileID;
|
||||
|
||||
// SourceManager doesn't support copy construction.
|
||||
explicit SourceManager(const SourceManager&);
|
||||
void operator=(const SourceManager&);
|
||||
public:
|
||||
SourceManager() : LastLineNoFileIDQuery(~0U), MainFileID(0) {}
|
||||
~SourceManager() {}
|
||||
|
||||
void clearIDTables() {
|
||||
FileIDs.clear();
|
||||
MacroIDs.clear();
|
||||
LastLineNoFileIDQuery = ~0U;
|
||||
LastLineNoContentCache = 0;
|
||||
}
|
||||
|
||||
/// getMainFileID - Returns the FileID of the main source file.
|
||||
unsigned getMainFileID() const { return MainFileID; }
|
||||
|
||||
/// createFileID - Create a new FileID that represents the specified file
|
||||
/// being #included from the specified IncludePosition. This returns 0 on
|
||||
/// error and translates NULL into standard input.
|
||||
unsigned createFileID(const FileEntry *SourceFile, SourceLocation IncludePos){
|
||||
const SrcMgr::ContentCache *IR = getContentCache(SourceFile);
|
||||
if (IR == 0) return 0; // Error opening file?
|
||||
return createFileID(IR, IncludePos);
|
||||
}
|
||||
|
||||
/// createMainFileID - Create the FileID for the main source file.
|
||||
unsigned createMainFileID(const FileEntry *SourceFile,
|
||||
SourceLocation IncludePos) {
|
||||
|
||||
assert (MainFileID == 0 && "MainFileID already set!");
|
||||
MainFileID = createFileID(SourceFile,IncludePos);
|
||||
return MainFileID;
|
||||
}
|
||||
|
||||
/// createFileIDForMemBuffer - Create a new FileID that represents the
|
||||
/// specified memory buffer. This does no caching of the buffer and takes
|
||||
/// ownership of the MemoryBuffer, so only pass a MemoryBuffer to this once.
|
||||
unsigned createFileIDForMemBuffer(const llvm::MemoryBuffer *Buffer) {
|
||||
return createFileID(createMemBufferContentCache(Buffer), SourceLocation());
|
||||
}
|
||||
|
||||
/// createMainFileIDForMembuffer - Create the FileID for a memory buffer
|
||||
/// that will represent the FileID for the main source. One example
|
||||
/// of when this would be used is when the main source is read from STDIN.
|
||||
unsigned createMainFileIDForMemBuffer(const llvm::MemoryBuffer *Buffer) {
|
||||
assert (MainFileID == 0 && "MainFileID already set!");
|
||||
MainFileID = createFileIDForMemBuffer(Buffer);
|
||||
return MainFileID;
|
||||
}
|
||||
|
||||
/// getInstantiationLoc - Return a new SourceLocation that encodes the fact
|
||||
/// that a token at Loc should actually be referenced from InstantiationLoc.
|
||||
SourceLocation getInstantiationLoc(SourceLocation Loc,
|
||||
SourceLocation InstantiationLoc);
|
||||
|
||||
/// getBuffer - Return the buffer for the specified FileID.
|
||||
///
|
||||
const llvm::MemoryBuffer *getBuffer(unsigned FileID) const {
|
||||
return getContentCache(FileID)->Buffer;
|
||||
}
|
||||
|
||||
/// getBufferData - Return a pointer to the start and end of the character
|
||||
/// data for the specified FileID.
|
||||
std::pair<const char*, const char*> getBufferData(unsigned FileID) const;
|
||||
|
||||
/// getIncludeLoc - Return the location of the #include for the specified
|
||||
/// SourceLocation. If this is a macro expansion, this transparently figures
|
||||
/// out which file includes the file being expanded into.
|
||||
SourceLocation getIncludeLoc(SourceLocation ID) const {
|
||||
return getFIDInfo(getLogicalLoc(ID).getFileID())->getIncludeLoc();
|
||||
}
|
||||
|
||||
/// getCharacterData - Return a pointer to the start of the specified location
|
||||
/// in the appropriate MemoryBuffer.
|
||||
const char *getCharacterData(SourceLocation SL) const;
|
||||
|
||||
/// getColumnNumber - Return the column # for the specified file position.
|
||||
/// This is significantly cheaper to compute than the line number. This
|
||||
/// returns zero if the column number isn't known. This may only be called on
|
||||
/// a file sloc, so you must choose a physical or logical location before
|
||||
/// calling this method.
|
||||
unsigned getColumnNumber(SourceLocation Loc) const;
|
||||
|
||||
unsigned getPhysicalColumnNumber(SourceLocation Loc) const {
|
||||
return getColumnNumber(getPhysicalLoc(Loc));
|
||||
}
|
||||
unsigned getLogicalColumnNumber(SourceLocation Loc) const {
|
||||
return getColumnNumber(getLogicalLoc(Loc));
|
||||
}
|
||||
|
||||
|
||||
/// getLineNumber - Given a SourceLocation, return the physical line number
|
||||
/// for the position indicated. This requires building and caching a table of
|
||||
/// line offsets for the MemoryBuffer, so this is not cheap: use only when
|
||||
/// about to emit a diagnostic.
|
||||
unsigned getLineNumber(SourceLocation Loc);
|
||||
|
||||
unsigned getLogicalLineNumber(SourceLocation Loc) {
|
||||
return getLineNumber(getLogicalLoc(Loc));
|
||||
}
|
||||
unsigned getPhysicalLineNumber(SourceLocation Loc) {
|
||||
return getLineNumber(getPhysicalLoc(Loc));
|
||||
}
|
||||
|
||||
/// getSourceName - This method returns the name of the file or buffer that
|
||||
/// the SourceLocation specifies. This can be modified with #line directives,
|
||||
/// etc.
|
||||
const char *getSourceName(SourceLocation Loc) const;
|
||||
|
||||
/// Given a SourceLocation object, return the logical location referenced by
|
||||
/// the ID. This logical location is subject to #line directives, etc.
|
||||
SourceLocation getLogicalLoc(SourceLocation Loc) const {
|
||||
// File locations are both physical and logical.
|
||||
if (Loc.isFileID()) return Loc;
|
||||
|
||||
return MacroIDs[Loc.getMacroID()].getVirtualLoc();
|
||||
}
|
||||
|
||||
/// getPhysicalLoc - Given a SourceLocation object, return the physical
|
||||
/// location referenced by the ID.
|
||||
SourceLocation getPhysicalLoc(SourceLocation Loc) const {
|
||||
// File locations are both physical and logical.
|
||||
if (Loc.isFileID()) return Loc;
|
||||
|
||||
SourceLocation PLoc = MacroIDs[Loc.getMacroID()].getPhysicalLoc();
|
||||
return PLoc.getFileLocWithOffset(Loc.getMacroPhysOffs());
|
||||
}
|
||||
|
||||
/// getContentCacheForLoc - Return the ContentCache for the physloc of the
|
||||
/// specified SourceLocation, if one exists.
|
||||
const SrcMgr::ContentCache* getContentCacheForLoc(SourceLocation Loc) const {
|
||||
Loc = getPhysicalLoc(Loc);
|
||||
unsigned FileID = Loc.getFileID();
|
||||
assert(FileID-1 < FileIDs.size() && "Invalid FileID!");
|
||||
return FileIDs[FileID-1].getContentCache();
|
||||
}
|
||||
|
||||
/// getFileEntryForLoc - Return the FileEntry record for the physloc of the
|
||||
/// specified SourceLocation, if one exists.
|
||||
const FileEntry* getFileEntryForLoc(SourceLocation Loc) const {
|
||||
return getContentCacheForLoc(Loc)->Entry;
|
||||
}
|
||||
|
||||
/// getFileEntryForID - Returns the FileEntry record for the provided FileID.
|
||||
const FileEntry* getFileEntryForID(unsigned id) const {
|
||||
return getContentCache(id)->Entry;
|
||||
}
|
||||
|
||||
/// getCanonicalFileID - Return the canonical FileID for a SourceLocation.
|
||||
/// A file can have multiple FileIDs if it is large enough to be broken
|
||||
/// into multiple chunks. This method returns the unique FileID without
|
||||
/// chunk information for a given SourceLocation. Use this method when
|
||||
/// you want to compare FileIDs across SourceLocations.
|
||||
unsigned getCanonicalFileID(SourceLocation PhysLoc) const {
|
||||
return getDecomposedFileLoc(PhysLoc).first;
|
||||
}
|
||||
|
||||
/// getDecomposedFileLoc - Decompose the specified file location into a raw
|
||||
/// FileID + Offset pair. The first element is the FileID, the second is the
|
||||
/// offset from the start of the buffer of the location.
|
||||
std::pair<unsigned, unsigned> getDecomposedFileLoc(SourceLocation Loc) const {
|
||||
assert(Loc.isFileID() && "Isn't a File SourceLocation");
|
||||
|
||||
// TODO: Add a flag "is first chunk" to SLOC.
|
||||
const SrcMgr::FileIDInfo *FIDInfo = getFIDInfo(Loc.getFileID());
|
||||
|
||||
// If this file has been split up into chunks, factor in the chunk number
|
||||
// that the FileID references.
|
||||
unsigned ChunkNo = FIDInfo->getChunkNo();
|
||||
unsigned Offset = Loc.getRawFilePos();
|
||||
Offset += (ChunkNo << SourceLocation::FilePosBits);
|
||||
|
||||
return std::pair<unsigned,unsigned>(Loc.getFileID()-ChunkNo, Offset);
|
||||
}
|
||||
|
||||
/// getFullFilePos - This (efficient) method returns the offset from the start
|
||||
/// of the file that the specified physical SourceLocation represents. This
|
||||
/// returns the location of the physical character data, not the logical file
|
||||
/// position.
|
||||
unsigned getFullFilePos(SourceLocation PhysLoc) const {
|
||||
return getDecomposedFileLoc(PhysLoc).second;
|
||||
}
|
||||
|
||||
/// isFromSameFile - Returns true if both SourceLocations correspond to
|
||||
/// the same file.
|
||||
bool isFromSameFile(SourceLocation Loc1, SourceLocation Loc2) const {
|
||||
return getCanonicalFileID(Loc1) == getCanonicalFileID(Loc2);
|
||||
}
|
||||
|
||||
/// isFromMainFile - Returns true if the file of provided SourceLocation is
|
||||
/// the main file.
|
||||
bool isFromMainFile(SourceLocation Loc) const {
|
||||
return getCanonicalFileID(Loc) == getMainFileID();
|
||||
}
|
||||
|
||||
/// PrintStats - Print statistics to stderr.
|
||||
///
|
||||
void PrintStats() const;
|
||||
|
||||
/// Emit - Emit this SourceManager to Bitcode.
|
||||
void Emit(llvm::Serializer& S) const;
|
||||
|
||||
/// Read - Reconstitute a SourceManager from Bitcode.
|
||||
static SourceManager* CreateAndRegister(llvm::Deserializer& S,
|
||||
FileManager &FMgr);
|
||||
|
||||
private:
|
||||
friend class SrcMgr::ContentCache; // Used for deserialization.
|
||||
|
||||
/// createFileID - Create a new fileID for the specified ContentCache and
|
||||
/// include position. This works regardless of whether the ContentCache
|
||||
/// corresponds to a file or some other input source.
|
||||
unsigned createFileID(const SrcMgr::ContentCache* File,
|
||||
SourceLocation IncludePos);
|
||||
|
||||
/// getContentCache - Create or return a cached ContentCache for the specified
|
||||
/// file. This returns null on failure.
|
||||
const SrcMgr::ContentCache* getContentCache(const FileEntry* SourceFile);
|
||||
|
||||
/// createMemBufferContentCache - Create a new ContentCache for the specified
|
||||
/// memory buffer.
|
||||
const SrcMgr::ContentCache*
|
||||
createMemBufferContentCache(const llvm::MemoryBuffer* Buf);
|
||||
|
||||
const SrcMgr::FileIDInfo* getFIDInfo(unsigned FileID) const {
|
||||
assert(FileID-1 < FileIDs.size() && "Invalid FileID!");
|
||||
return &FileIDs[FileID-1];
|
||||
}
|
||||
|
||||
const SrcMgr::ContentCache *getContentCache(unsigned FileID) const {
|
||||
return getContentCache(getFIDInfo(FileID));
|
||||
}
|
||||
|
||||
/// Return the ContentCache structure for the specified FileID.
|
||||
/// This is always the physical reference for the ID.
|
||||
const SrcMgr::ContentCache*
|
||||
getContentCache(const SrcMgr::FileIDInfo* FIDInfo) const {
|
||||
return FIDInfo->getContentCache();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
@@ -1,222 +0,0 @@
|
||||
//===--- TargetInfo.h - Expose information about the target -----*- 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 TargetInfo interface.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_BASIC_TARGETINFO_H
|
||||
#define LLVM_CLANG_BASIC_TARGETINFO_H
|
||||
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace llvm { struct fltSemantics; }
|
||||
|
||||
namespace clang {
|
||||
|
||||
class Diagnostic;
|
||||
class SourceManager;
|
||||
|
||||
namespace Builtin { struct Info; }
|
||||
|
||||
/// TargetInfo - This class exposes information about the current target.
|
||||
///
|
||||
class TargetInfo {
|
||||
std::string Triple;
|
||||
protected:
|
||||
// Target values set by the ctor of the actual target implementation. Default
|
||||
// values are specified by the TargetInfo constructor.
|
||||
bool CharIsSigned;
|
||||
unsigned char PointerWidth, PointerAlign;
|
||||
unsigned char WCharWidth, WCharAlign;
|
||||
unsigned char IntWidth, IntAlign;
|
||||
unsigned char DoubleWidth, DoubleAlign;
|
||||
unsigned char LongWidth, LongAlign;
|
||||
unsigned char LongLongWidth, LongLongAlign;
|
||||
|
||||
const llvm::fltSemantics *FloatFormat, *DoubleFormat, *LongDoubleFormat;
|
||||
|
||||
// TargetInfo Constructor. Default initializes all fields.
|
||||
TargetInfo(const std::string &T);
|
||||
|
||||
public:
|
||||
/// CreateTargetInfo - Return the target info object for the specified target
|
||||
/// triple.
|
||||
static TargetInfo* CreateTargetInfo(const std::string &Triple);
|
||||
|
||||
virtual ~TargetInfo();
|
||||
|
||||
///===---- Target Data Type Query Methods -------------------------------===//
|
||||
|
||||
/// isCharSigned - Return true if 'char' is 'signed char' or false if it is
|
||||
/// treated as 'unsigned char'. This is implementation defined according to
|
||||
/// C99 6.2.5p15. In our implementation, this is target-specific.
|
||||
bool isCharSigned() const { return CharIsSigned; }
|
||||
|
||||
/// getPointerWidth - Return the width of pointers on this target, for the
|
||||
/// specified address space.
|
||||
uint64_t getPointerWidth(unsigned AddrSpace) const {
|
||||
return AddrSpace == 0 ? PointerWidth : getPointerWidthV(AddrSpace);
|
||||
}
|
||||
uint64_t getPointerAlign(unsigned AddrSpace) const {
|
||||
return AddrSpace == 0 ? PointerAlign : getPointerAlignV(AddrSpace);
|
||||
}
|
||||
virtual uint64_t getPointerWidthV(unsigned AddrSpace) const {
|
||||
return PointerWidth;
|
||||
}
|
||||
virtual uint64_t getPointerAlignV(unsigned AddrSpace) const {
|
||||
return PointerAlign;
|
||||
}
|
||||
|
||||
/// getBoolWidth/Align - Return the size of '_Bool' and C++ 'bool' for this
|
||||
/// target, in bits.
|
||||
unsigned getBoolWidth(bool isWide = false) const { return 8; } // FIXME
|
||||
unsigned getBoolAlign(bool isWide = false) const { return 8; } // FIXME
|
||||
|
||||
unsigned getCharWidth(bool isWide = false) const {
|
||||
return isWide ? getWCharWidth() : 8; // FIXME
|
||||
}
|
||||
unsigned getCharAlign(bool isWide = false) const {
|
||||
return isWide ? getWCharAlign() : 8; // FIXME
|
||||
}
|
||||
|
||||
/// getShortWidth/Align - Return the size of 'signed short' and
|
||||
/// 'unsigned short' for this target, in bits.
|
||||
unsigned getShortWidth() const { return 16; } // FIXME
|
||||
unsigned getShortAlign() const { return 16; } // FIXME
|
||||
|
||||
/// getIntWidth/Align - Return the size of 'signed int' and 'unsigned int' for
|
||||
/// this target, in bits.
|
||||
unsigned getIntWidth() const { return IntWidth; }
|
||||
unsigned getIntAlign() const { return IntAlign; }
|
||||
|
||||
/// getLongWidth/Align - Return the size of 'signed long' and 'unsigned long'
|
||||
/// for this target, in bits.
|
||||
unsigned getLongWidth() const { return LongWidth; }
|
||||
unsigned getLongAlign() const { return LongAlign; }
|
||||
|
||||
/// getLongLongWidth/Align - Return the size of 'signed long long' and
|
||||
/// 'unsigned long long' for this target, in bits.
|
||||
unsigned getLongLongWidth() const { return LongLongWidth; }
|
||||
unsigned getLongLongAlign() const { return LongLongAlign; }
|
||||
|
||||
/// getWcharWidth/Align - Return the size of 'wchar_t' for this target, in
|
||||
/// bits.
|
||||
unsigned getWCharWidth() const { return WCharWidth; }
|
||||
unsigned getWCharAlign() const { return WCharAlign; }
|
||||
|
||||
/// getFloatWidth/Align/Format - Return the size/align/format of 'float'.
|
||||
unsigned getFloatWidth() const { return 32; } // FIXME
|
||||
unsigned getFloatAlign() const { return 32; } // FIXME
|
||||
const llvm::fltSemantics *getFloatFormat() const { return FloatFormat; }
|
||||
|
||||
/// getDoubleWidth/Align/Format - Return the size/align/format of 'double'.
|
||||
unsigned getDoubleWidth() const { return DoubleWidth; }
|
||||
unsigned getDoubleAlign() const { return DoubleAlign; }
|
||||
const llvm::fltSemantics *getDoubleFormat() const { return DoubleFormat; }
|
||||
|
||||
/// getLongDoubleWidth/Align/Format - Return the size/align/format of 'long
|
||||
/// double'.
|
||||
unsigned getLongDoubleWidth() const { return 64; } // FIXME
|
||||
unsigned getLongDoubleAlign() const { return 64; } // FIXME
|
||||
const llvm::fltSemantics *getLongDoubleFormat() const {
|
||||
return LongDoubleFormat;
|
||||
}
|
||||
|
||||
/// getIntMaxTWidth - Return the size of intmax_t and uintmax_t for this
|
||||
/// target, in bits.
|
||||
unsigned getIntMaxTWidth() const {
|
||||
// FIXME: implement correctly.
|
||||
return 64;
|
||||
}
|
||||
|
||||
///===---- Other target property query methods --------------------------===//
|
||||
|
||||
/// getTargetDefines - Appends the target-specific #define values for this
|
||||
/// target set to the specified buffer.
|
||||
virtual void getTargetDefines(std::vector<char> &DefineBuffer) const = 0;
|
||||
|
||||
/// getTargetBuiltins - Return information about target-specific builtins for
|
||||
/// the current primary target, and info about which builtins are non-portable
|
||||
/// across the current set of primary and secondary targets.
|
||||
virtual void getTargetBuiltins(const Builtin::Info *&Records,
|
||||
unsigned &NumRecords) const = 0;
|
||||
|
||||
/// getVAListDeclaration - Return the declaration to use for
|
||||
/// __builtin_va_list, which is target-specific.
|
||||
virtual const char *getVAListDeclaration() const = 0;
|
||||
|
||||
/// isValidGCCRegisterName - Returns whether the passed in string
|
||||
/// is a valid register name according to GCC. This is used by Sema for
|
||||
/// inline asm statements.
|
||||
bool isValidGCCRegisterName(const char *Name) const;
|
||||
|
||||
// getNormalizedGCCRegisterName - Returns the "normalized" GCC register name.
|
||||
// For example, on x86 it will return "ax" when "eax" is passed in.
|
||||
const char *getNormalizedGCCRegisterName(const char *Name) const;
|
||||
|
||||
enum ConstraintInfo {
|
||||
CI_None = 0x00,
|
||||
CI_AllowsMemory = 0x01,
|
||||
CI_AllowsRegister = 0x02,
|
||||
CI_ReadWrite = 0x04
|
||||
};
|
||||
|
||||
// validateOutputConstraint, validateInputConstraint - Checks that
|
||||
// a constraint is valid and provides information about it.
|
||||
// FIXME: These should return a real error instead of just true/false.
|
||||
bool validateOutputConstraint(const char *Name, ConstraintInfo &Info) const;
|
||||
bool validateInputConstraint (const char *Name, unsigned NumOutputs,
|
||||
ConstraintInfo &info) const;
|
||||
|
||||
virtual std::string convertConstraint(const char Constraint) const {
|
||||
return std::string(1, Constraint);
|
||||
}
|
||||
|
||||
// Returns a string of target-specific clobbers, in LLVM format.
|
||||
virtual const char *getClobbers() const = 0;
|
||||
|
||||
|
||||
/// getTargetPrefix - Return the target prefix used for identifying
|
||||
/// llvm intrinsics.
|
||||
virtual const char *getTargetPrefix() const = 0;
|
||||
|
||||
/// getTargetTriple - Return the target triple of the primary target.
|
||||
const char *getTargetTriple() const {
|
||||
return Triple.c_str();
|
||||
}
|
||||
|
||||
const char *getTargetDescription() const {
|
||||
// FIXME !
|
||||
// Hard code darwin-x86 for now.
|
||||
return "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:\
|
||||
32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128";
|
||||
}
|
||||
|
||||
struct GCCRegAlias {
|
||||
const char * const Aliases[5];
|
||||
const char * const Register;
|
||||
};
|
||||
|
||||
virtual bool useGlobalsForAutomaticVariables() const {return false;}
|
||||
|
||||
protected:
|
||||
virtual void getGCCRegNames(const char * const *&Names,
|
||||
unsigned &NumNames) const = 0;
|
||||
virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
|
||||
unsigned &NumAliases) const = 0;
|
||||
virtual bool validateAsmConstraint(char c,
|
||||
TargetInfo::ConstraintInfo &info) const= 0;
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
@@ -1,364 +0,0 @@
|
||||
//===--- TokenKinds.def - C Family Token Kind 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 TokenKind database. This includes normal tokens like
|
||||
// tok::ampamp (corresponding to the && token) as well as keywords for various
|
||||
// languages. Users of this file must optionally #define the TOK, KEYWORD,
|
||||
// ALIAS, or PPKEYWORD macros to make use of this file.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef TOK
|
||||
#define TOK(X)
|
||||
#endif
|
||||
#ifndef KEYWORD
|
||||
#define KEYWORD(X,Y) TOK(kw_ ## X)
|
||||
#endif
|
||||
#ifndef ALIAS
|
||||
#define ALIAS(X,Y)
|
||||
#endif
|
||||
#ifndef PPKEYWORD
|
||||
#define PPKEYWORD(X)
|
||||
#endif
|
||||
#ifndef CXX_KEYWORD_OPERATOR
|
||||
#define CXX_KEYWORD_OPERATOR(X,Y)
|
||||
#endif
|
||||
#ifndef OBJC1_AT_KEYWORD
|
||||
#define OBJC1_AT_KEYWORD(X)
|
||||
#endif
|
||||
#ifndef OBJC2_AT_KEYWORD
|
||||
#define OBJC2_AT_KEYWORD(X)
|
||||
#endif
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Preprocessor keywords.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// These have meaning after a '#' at the start of a line. These define enums in
|
||||
// the tok::pp_* namespace. Note that IdentifierInfo::getPPKeywordID must be
|
||||
// manually updated if something is added here.
|
||||
PPKEYWORD(not_keyword)
|
||||
|
||||
// C99 6.10.1 - Conditional Inclusion.
|
||||
PPKEYWORD(if)
|
||||
PPKEYWORD(ifdef)
|
||||
PPKEYWORD(ifndef)
|
||||
PPKEYWORD(elif)
|
||||
PPKEYWORD(else)
|
||||
PPKEYWORD(endif)
|
||||
PPKEYWORD(defined)
|
||||
|
||||
// C99 6.10.2 - Source File Inclusion.
|
||||
PPKEYWORD(include)
|
||||
|
||||
// C99 6.10.3 - Macro Replacement.
|
||||
PPKEYWORD(define)
|
||||
PPKEYWORD(undef)
|
||||
|
||||
// C99 6.10.4 - Line Control.
|
||||
PPKEYWORD(line)
|
||||
|
||||
// C99 6.10.5 - Error Directive.
|
||||
PPKEYWORD(error)
|
||||
|
||||
// C99 6.10.6 - Pragma Directive.
|
||||
PPKEYWORD(pragma)
|
||||
|
||||
// GNU Extensions.
|
||||
PPKEYWORD(import)
|
||||
PPKEYWORD(include_next)
|
||||
PPKEYWORD(warning)
|
||||
PPKEYWORD(ident)
|
||||
PPKEYWORD(sccs)
|
||||
PPKEYWORD(assert)
|
||||
PPKEYWORD(unassert)
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Language keywords.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// These define members of the tok::* namespace.
|
||||
|
||||
TOK(unknown) // Not a token.
|
||||
TOK(eof) // End of file.
|
||||
TOK(eom) // End of macro (end of line inside a macro).
|
||||
|
||||
// C99 6.4.9: Comments.
|
||||
TOK(comment) // Comment (only in -E -C[C] mode)
|
||||
|
||||
// C99 6.4.2: Identifiers.
|
||||
TOK(identifier) // abcde123
|
||||
|
||||
// C99 6.4.4.1: Integer Constants
|
||||
// C99 6.4.4.2: Floating Constants
|
||||
TOK(numeric_constant) // 0x123
|
||||
|
||||
// C99 6.4.4: Character Constants
|
||||
TOK(char_constant) // 'a' L'b'
|
||||
|
||||
// C99 6.4.5: String Literals.
|
||||
TOK(string_literal) // "foo"
|
||||
TOK(wide_string_literal) // L"foo"
|
||||
TOK(angle_string_literal)// <foo>
|
||||
|
||||
// C99 6.4.6: Punctuators.
|
||||
TOK(l_square) // [
|
||||
TOK(r_square) // ]
|
||||
TOK(l_paren) // (
|
||||
TOK(r_paren) // )
|
||||
TOK(l_brace) // {
|
||||
TOK(r_brace) // }
|
||||
TOK(period) // .
|
||||
TOK(ellipsis) // ...
|
||||
TOK(amp) // &
|
||||
TOK(ampamp) // &&
|
||||
TOK(ampequal) // &=
|
||||
TOK(star) // *
|
||||
TOK(starequal) // *=
|
||||
TOK(plus) // +
|
||||
TOK(plusplus) // ++
|
||||
TOK(plusequal) // +=
|
||||
TOK(minus) // -
|
||||
TOK(arrow) // ->
|
||||
TOK(minusminus) // --
|
||||
TOK(minusequal) // -=
|
||||
TOK(tilde) // ~
|
||||
TOK(exclaim) // !
|
||||
TOK(exclaimequal) // !=
|
||||
TOK(slash) // /
|
||||
TOK(slashequal) // /=
|
||||
TOK(percent) // %
|
||||
TOK(percentequal) // %=
|
||||
TOK(less) // <
|
||||
TOK(lessless) // <<
|
||||
TOK(lessequal) // <=
|
||||
TOK(lesslessequal) // <<=
|
||||
TOK(greater) // >
|
||||
TOK(greatergreater) // >>
|
||||
TOK(greaterequal) // >=
|
||||
TOK(greatergreaterequal) // >>=
|
||||
TOK(caret) // ^
|
||||
TOK(caretequal) // ^=
|
||||
TOK(pipe) // |
|
||||
TOK(pipepipe) // ||
|
||||
TOK(pipeequal) // |=
|
||||
TOK(question) // ?
|
||||
TOK(colon) // :
|
||||
TOK(semi) // ;
|
||||
TOK(equal) // =
|
||||
TOK(equalequal) // ==
|
||||
TOK(comma) // ,
|
||||
TOK(hash) // #
|
||||
TOK(hashhash) // ##
|
||||
TOK(hashat) // #@
|
||||
|
||||
// C++ Support
|
||||
TOK(periodstar) // .*
|
||||
TOK(arrowstar) // ->*
|
||||
TOK(coloncolon) // ::
|
||||
|
||||
// Objective C support.
|
||||
TOK(at) // @
|
||||
|
||||
|
||||
// C99 6.4.1: Keywords. These turn into kw_* tokens.
|
||||
// Flags allowed:
|
||||
// NOTC90 - In C90, this token is never available.
|
||||
// EXTC90 - In C90, this token is an extension that is enabled unless strict.
|
||||
// NOTC99 - In C99, this token is never available.
|
||||
// EXTC99 - In C99, this token is an extension that is enabled unless strict.
|
||||
// NOTCPP - In C++98, this token is never available.
|
||||
// EXTCPP - In C++98, this token is an extension that is enabled unless strict.
|
||||
// NOTCPP0x - In C++0x, this token is never available.
|
||||
// EXTCPP0x - In C++0x, this token is an extension that is enabled unless
|
||||
// strict.
|
||||
//
|
||||
KEYWORD(auto , 0)
|
||||
KEYWORD(break , 0)
|
||||
KEYWORD(case , 0)
|
||||
KEYWORD(char , 0)
|
||||
KEYWORD(const , 0)
|
||||
KEYWORD(continue , 0)
|
||||
KEYWORD(default , 0)
|
||||
KEYWORD(do , 0)
|
||||
KEYWORD(double , 0)
|
||||
KEYWORD(else , 0)
|
||||
KEYWORD(enum , 0)
|
||||
KEYWORD(extern , 0)
|
||||
KEYWORD(float , 0)
|
||||
KEYWORD(for , 0)
|
||||
KEYWORD(goto , 0)
|
||||
KEYWORD(if , 0)
|
||||
KEYWORD(inline , EXTC90) // Ext in C90, ok in C99/C++
|
||||
KEYWORD(int , 0)
|
||||
KEYWORD(long , 0)
|
||||
KEYWORD(register , 0)
|
||||
KEYWORD(restrict , NOTC90) // Not in C90
|
||||
KEYWORD(return , 0)
|
||||
KEYWORD(short , 0)
|
||||
KEYWORD(signed , 0)
|
||||
KEYWORD(sizeof , 0)
|
||||
KEYWORD(static , 0)
|
||||
KEYWORD(struct , 0)
|
||||
KEYWORD(switch , 0)
|
||||
KEYWORD(typedef , 0)
|
||||
KEYWORD(union , 0)
|
||||
KEYWORD(unsigned , 0)
|
||||
KEYWORD(void , 0)
|
||||
KEYWORD(volatile , 0)
|
||||
KEYWORD(while , 0)
|
||||
KEYWORD(_Bool , EXTC90|EXTCPP|EXTCPP0x) // C99 only
|
||||
KEYWORD(_Complex , EXTC90|EXTCPP|EXTCPP0x) // C99 only
|
||||
KEYWORD(_Imaginary , EXTC90|NOTCPP|NOTCPP0x) // C90 only
|
||||
|
||||
// Special tokens to the compiler.
|
||||
KEYWORD(__func__ , EXTC90|EXTCPP|EXTCPP0x) // Only in C99.
|
||||
KEYWORD(__FUNCTION__ , EXTC90|EXTC99|EXTCPP|EXTCPP0x) // GCC Extension.
|
||||
KEYWORD(__PRETTY_FUNCTION__ , EXTC90|EXTC99|EXTCPP|EXTCPP0x) // GCC Extension.
|
||||
|
||||
// C++ 2.11p1: Keywords.
|
||||
KEYWORD(asm , EXTC90|EXTC99) // Exts in C90/C99
|
||||
KEYWORD(bool , BOOLSUPPORT)
|
||||
KEYWORD(catch , NOTC90|NOTC99)
|
||||
KEYWORD(class , NOTC90|NOTC99)
|
||||
KEYWORD(const_cast , NOTC90|NOTC99)
|
||||
KEYWORD(delete , NOTC90|NOTC99)
|
||||
KEYWORD(dynamic_cast , NOTC90|NOTC99)
|
||||
KEYWORD(explicit , NOTC90|NOTC99)
|
||||
KEYWORD(export , NOTC90|NOTC99)
|
||||
KEYWORD(false , BOOLSUPPORT)
|
||||
KEYWORD(friend , NOTC90|NOTC99)
|
||||
KEYWORD(mutable , NOTC90|NOTC99)
|
||||
KEYWORD(namespace , NOTC90|NOTC99)
|
||||
KEYWORD(new , NOTC90|NOTC99)
|
||||
KEYWORD(operator , NOTC90|NOTC99)
|
||||
KEYWORD(private , NOTC90|NOTC99)
|
||||
KEYWORD(protected , NOTC90|NOTC99)
|
||||
KEYWORD(public , NOTC90|NOTC99)
|
||||
KEYWORD(reinterpret_cast , NOTC90|NOTC99)
|
||||
KEYWORD(static_cast , NOTC90|NOTC99)
|
||||
KEYWORD(template , NOTC90|NOTC99)
|
||||
KEYWORD(this , NOTC90|NOTC99)
|
||||
KEYWORD(throw , NOTC90|NOTC99)
|
||||
KEYWORD(true , BOOLSUPPORT)
|
||||
KEYWORD(try , NOTC90|NOTC99)
|
||||
KEYWORD(typename , NOTC90|NOTC99)
|
||||
KEYWORD(typeid , NOTC90|NOTC99)
|
||||
KEYWORD(using , NOTC90|NOTC99)
|
||||
KEYWORD(virtual , NOTC90|NOTC99)
|
||||
KEYWORD(wchar_t , NOTC90|NOTC99)
|
||||
|
||||
// C++ 2.5p2: Alternative Representations.
|
||||
CXX_KEYWORD_OPERATOR(and , ampamp)
|
||||
CXX_KEYWORD_OPERATOR(and_eq , ampequal)
|
||||
CXX_KEYWORD_OPERATOR(bitand , amp)
|
||||
CXX_KEYWORD_OPERATOR(bitor , pipe)
|
||||
CXX_KEYWORD_OPERATOR(compl , tilde)
|
||||
CXX_KEYWORD_OPERATOR(not , exclaim)
|
||||
CXX_KEYWORD_OPERATOR(not_eq , exclaimequal)
|
||||
CXX_KEYWORD_OPERATOR(or , pipepipe)
|
||||
CXX_KEYWORD_OPERATOR(or_eq , pipeequal)
|
||||
CXX_KEYWORD_OPERATOR(xor , caret)
|
||||
CXX_KEYWORD_OPERATOR(xor_eq , caretequal)
|
||||
|
||||
// C++0x keywords
|
||||
KEYWORD(char16_t , NOTC90|NOTC99|NOTCPP)
|
||||
KEYWORD(char32_t , NOTC90|NOTC99|NOTCPP)
|
||||
KEYWORD(static_assert , NOTC90|NOTC99|NOTCPP)
|
||||
|
||||
// GNU Extensions.
|
||||
KEYWORD(_Decimal32 , EXTC90|EXTC99|EXTCPP|EXTCPP0x)
|
||||
KEYWORD(_Decimal64 , EXTC90|EXTC99|EXTCPP|EXTCPP0x)
|
||||
KEYWORD(_Decimal128 , EXTC90|EXTC99|EXTCPP|EXTCPP0x)
|
||||
KEYWORD(typeof , EXTC90|EXTC99|EXTCPP|EXTCPP0x)
|
||||
KEYWORD(__null , NOTC90|NOTC99|EXTCPP|EXTCPP0x) // C++-only Extensn
|
||||
KEYWORD(__alignof , EXTC90|EXTC99|EXTCPP|EXTCPP0x)
|
||||
KEYWORD(__attribute , EXTC90|EXTC99|EXTCPP|EXTCPP0x)
|
||||
KEYWORD(__builtin_choose_expr , EXTC90|EXTC99|EXTCPP|EXTCPP0x)
|
||||
KEYWORD(__builtin_overload , EXTC90|EXTC99|EXTCPP|EXTCPP0x)
|
||||
KEYWORD(__builtin_offsetof , EXTC90|EXTC99|EXTCPP|EXTCPP0x)
|
||||
KEYWORD(__builtin_types_compatible_p, EXTC90|EXTC99|EXTCPP|EXTCPP0x)
|
||||
KEYWORD(__builtin_va_arg , EXTC90|EXTC99|EXTCPP|EXTCPP0x)
|
||||
KEYWORD(__extension__ , 0) // Not treated as an extension!
|
||||
KEYWORD(__imag , EXTC90|EXTC99|EXTCPP|EXTCPP0x)
|
||||
KEYWORD(__label__ , EXTC90|EXTC99|EXTCPP|EXTCPP0x)
|
||||
KEYWORD(__real , EXTC90|EXTC99|EXTCPP|EXTCPP0x)
|
||||
KEYWORD(__thread , EXTC90|EXTC99|EXTCPP|EXTCPP0x)
|
||||
|
||||
// Apple Extension.
|
||||
KEYWORD(__private_extern__ , EXTC90|EXTC99|NOTCPP)
|
||||
|
||||
// Alternate spelling for various tokens. There are GCC extensions in all
|
||||
// languages, but should not be disabled in strict conformance mode.
|
||||
ALIAS("__attribute__", __attribute)
|
||||
ALIAS("__const" , const )
|
||||
ALIAS("__const__" , const )
|
||||
ALIAS("__alignof__" , __alignof )
|
||||
ALIAS("_asm" , asm )
|
||||
ALIAS("__asm" , asm )
|
||||
ALIAS("__asm__" , asm )
|
||||
ALIAS("__complex" , _Complex )
|
||||
ALIAS("__complex__" , _Complex )
|
||||
ALIAS("__imag__" , __imag )
|
||||
ALIAS("__inline" , inline )
|
||||
ALIAS("__inline__" , inline )
|
||||
ALIAS("__real__" , __real )
|
||||
ALIAS("__restrict" , restrict )
|
||||
ALIAS("__restrict__" , restrict )
|
||||
ALIAS("__signed" , signed )
|
||||
ALIAS("__signed__" , signed )
|
||||
ALIAS("__typeof" , typeof )
|
||||
ALIAS("__typeof__" , typeof )
|
||||
ALIAS("__volatile" , volatile )
|
||||
ALIAS("__volatile__" , volatile )
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Objective-C @-preceeded keywords.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// These have meaning after an '@' in Objective-C mode. These define enums in
|
||||
// the tok::objc_* namespace.
|
||||
|
||||
OBJC1_AT_KEYWORD(not_keyword)
|
||||
OBJC1_AT_KEYWORD(class)
|
||||
OBJC1_AT_KEYWORD(compatibility_alias)
|
||||
OBJC1_AT_KEYWORD(defs)
|
||||
OBJC1_AT_KEYWORD(encode)
|
||||
OBJC1_AT_KEYWORD(end)
|
||||
OBJC1_AT_KEYWORD(implementation)
|
||||
OBJC1_AT_KEYWORD(interface)
|
||||
OBJC1_AT_KEYWORD(private)
|
||||
OBJC1_AT_KEYWORD(protected)
|
||||
OBJC1_AT_KEYWORD(protocol)
|
||||
OBJC1_AT_KEYWORD(public)
|
||||
OBJC1_AT_KEYWORD(selector)
|
||||
OBJC1_AT_KEYWORD(throw)
|
||||
OBJC1_AT_KEYWORD(try)
|
||||
OBJC1_AT_KEYWORD(catch)
|
||||
OBJC1_AT_KEYWORD(finally)
|
||||
OBJC1_AT_KEYWORD(synchronized)
|
||||
|
||||
OBJC2_AT_KEYWORD(property)
|
||||
OBJC2_AT_KEYWORD(package)
|
||||
OBJC2_AT_KEYWORD(required)
|
||||
OBJC2_AT_KEYWORD(optional)
|
||||
OBJC2_AT_KEYWORD(synthesize)
|
||||
OBJC2_AT_KEYWORD(dynamic)
|
||||
|
||||
// TODO: What to do about context-sensitive keywords like:
|
||||
// bycopy/byref/in/inout/oneway/out?
|
||||
|
||||
#undef OBJC2_AT_KEYWORD
|
||||
#undef OBJC1_AT_KEYWORD
|
||||
#undef CXX_KEYWORD_OPERATOR
|
||||
#undef PPKEYWORD
|
||||
#undef ALIAS
|
||||
#undef KEYWORD
|
||||
#undef TOK
|
||||
@@ -1,51 +0,0 @@
|
||||
//===--- TokenKinds.h - Enum values for C Token Kinds -----------*- 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 TokenKind enum and support functions.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_TOKENKINDS_H
|
||||
#define LLVM_CLANG_TOKENKINDS_H
|
||||
|
||||
namespace clang {
|
||||
|
||||
namespace tok {
|
||||
|
||||
/// TokenKind - This provides a simple uniform namespace for tokens from all C
|
||||
/// languages.
|
||||
enum TokenKind {
|
||||
#define TOK(X) X,
|
||||
#include "clang/Basic/TokenKinds.def"
|
||||
NUM_TOKENS
|
||||
};
|
||||
|
||||
/// PPKeywordKind - This provides a namespace for preprocessor keywords which
|
||||
/// start with a '#' at the beginning of the line.
|
||||
enum PPKeywordKind {
|
||||
#define PPKEYWORD(X) pp_##X,
|
||||
#include "clang/Basic/TokenKinds.def"
|
||||
NUM_PP_KEYWORDS
|
||||
};
|
||||
|
||||
/// ObjCKeywordKind - This provides a namespace for Objective-C keywords which
|
||||
/// start with an '@'.
|
||||
enum ObjCKeywordKind {
|
||||
#define OBJC1_AT_KEYWORD(X) objc_##X,
|
||||
#define OBJC2_AT_KEYWORD(X) objc_##X,
|
||||
#include "clang/Basic/TokenKinds.def"
|
||||
NUM_OBJC_KEYWORDS
|
||||
};
|
||||
|
||||
const char *getTokenName(enum TokenKind Kind);
|
||||
|
||||
} // end namespace tok
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
@@ -1,31 +0,0 @@
|
||||
//===--- CodeGen/ModuleBuilder.h - Build LLVM from 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 ModuleBuilder interface.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_CODEGEN_MODULEBUILDER_H
|
||||
#define LLVM_CLANG_CODEGEN_MODULEBUILDER_H
|
||||
|
||||
namespace llvm {
|
||||
class Module;
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
class Diagnostic;
|
||||
struct LangOptions;
|
||||
class ASTConsumer;
|
||||
|
||||
ASTConsumer *CreateLLVMCodeGen(Diagnostic &Diags, const LangOptions &Features,
|
||||
llvm::Module *&DestModule,
|
||||
bool GenerateDebugInfo);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,135 +0,0 @@
|
||||
//===--- DirectoryLookup.h - Info for searching for headers -----*- 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 DirectoryLookup interface.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_LEX_DIRECTORYLOOKUP_H
|
||||
#define LLVM_CLANG_LEX_DIRECTORYLOOKUP_H
|
||||
|
||||
namespace clang {
|
||||
class HeaderMap;
|
||||
class DirectoryEntry;
|
||||
class FileEntry;
|
||||
class HeaderSearch;
|
||||
|
||||
/// DirectoryLookup - This class represents one entry in the search list that
|
||||
/// specifies the search order for directories in #include directives. It
|
||||
/// represents either a directory, a framework, or a headermap.
|
||||
///
|
||||
class DirectoryLookup {
|
||||
public:
|
||||
enum DirType {
|
||||
NormalHeaderDir,
|
||||
SystemHeaderDir,
|
||||
ExternCSystemHeaderDir
|
||||
};
|
||||
|
||||
enum LookupType_t {
|
||||
LT_NormalDir,
|
||||
LT_Framework,
|
||||
LT_HeaderMap
|
||||
};
|
||||
private:
|
||||
union { // This union is discriminated by isHeaderMap.
|
||||
/// Dir - This is the actual directory that we're referring to for a normal
|
||||
/// directory or a framework.
|
||||
const DirectoryEntry *Dir;
|
||||
|
||||
/// Map - This is the HeaderMap if this is a headermap lookup.
|
||||
///
|
||||
const HeaderMap *Map;
|
||||
} u;
|
||||
|
||||
// NOTE: VC++ treats enums as signed, avoid using the DirType enum
|
||||
/// DirCharacteristic - The type of directory this is, one of the DirType enum
|
||||
/// values.
|
||||
unsigned DirCharacteristic : 2;
|
||||
|
||||
/// UserSupplied - True if this is a user-supplied directory.
|
||||
///
|
||||
bool UserSupplied : 1;
|
||||
|
||||
/// LookupType - This indicates whether this DirectoryLookup object is a
|
||||
/// normal directory, a framework, or a headermap.
|
||||
unsigned LookupType : 2;
|
||||
public:
|
||||
/// DirectoryLookup ctor - Note that this ctor *does not take ownership* of
|
||||
/// 'dir'.
|
||||
DirectoryLookup(const DirectoryEntry *dir, DirType DT, bool isUser,
|
||||
bool isFramework)
|
||||
: DirCharacteristic(DT), UserSupplied(isUser),
|
||||
LookupType(isFramework ? LT_Framework : LT_NormalDir) {
|
||||
u.Dir = dir;
|
||||
}
|
||||
|
||||
/// DirectoryLookup ctor - Note that this ctor *does not take ownership* of
|
||||
/// 'map'.
|
||||
DirectoryLookup(const HeaderMap *map, DirType DT, bool isUser)
|
||||
: DirCharacteristic(DT), UserSupplied(isUser), LookupType(LT_HeaderMap) {
|
||||
u.Map = map;
|
||||
}
|
||||
|
||||
/// getLookupType - Return the kind of directory lookup that this is: either a
|
||||
/// normal directory, a framework path, or a HeaderMap.
|
||||
LookupType_t getLookupType() const { return (LookupType_t)LookupType; }
|
||||
|
||||
/// getName - Return the directory or filename corresponding to this lookup
|
||||
/// object.
|
||||
const char *getName() const;
|
||||
|
||||
/// getDir - Return the directory that this entry refers to.
|
||||
///
|
||||
const DirectoryEntry *getDir() const { return isNormalDir() ? u.Dir : 0; }
|
||||
|
||||
/// getFrameworkDir - Return the directory that this framework refers to.
|
||||
///
|
||||
const DirectoryEntry *getFrameworkDir() const {
|
||||
return isFramework() ? u.Dir : 0;
|
||||
}
|
||||
|
||||
/// getHeaderMap - Return the directory that this entry refers to.
|
||||
///
|
||||
const HeaderMap *getHeaderMap() const { return isHeaderMap() ? u.Map : 0; }
|
||||
|
||||
/// isNormalDir - Return true if this is a normal directory, not a header map.
|
||||
bool isNormalDir() const { return getLookupType() == LT_NormalDir; }
|
||||
|
||||
/// isFramework - True if this is a framework directory.
|
||||
///
|
||||
bool isFramework() const { return getLookupType() == LT_Framework; }
|
||||
|
||||
/// isHeaderMap - Return true if this is a header map, not a normal directory.
|
||||
bool isHeaderMap() const { return getLookupType() == LT_HeaderMap; }
|
||||
|
||||
/// DirCharacteristic - The type of directory this is, one of the DirType enum
|
||||
/// values.
|
||||
DirType getDirCharacteristic() const { return DirType(DirCharacteristic); }
|
||||
|
||||
/// isUserSupplied - True if this is a user-supplied directory.
|
||||
///
|
||||
bool isUserSupplied() const { return UserSupplied; }
|
||||
|
||||
|
||||
/// LookupFile - Lookup the specified file in this search path, returning it
|
||||
/// if it exists or returning null if not.
|
||||
const FileEntry *LookupFile(const char *FilenameStart,
|
||||
const char *FilenameEnd, HeaderSearch &HS) const;
|
||||
|
||||
private:
|
||||
const FileEntry *DoFrameworkLookup(const char *FilenameStart,
|
||||
const char *FilenameEnd,
|
||||
HeaderSearch &HS) const;
|
||||
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
@@ -1,67 +0,0 @@
|
||||
//===--- HeaderMap.h - A file that acts like dir of symlinks ----*- 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 HeaderMap interface.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_LEX_HEADERMAP_H
|
||||
#define LLVM_CLANG_LEX_HEADERMAP_H
|
||||
|
||||
namespace llvm {
|
||||
class MemoryBuffer;
|
||||
}
|
||||
namespace clang {
|
||||
class FileEntry;
|
||||
class FileManager;
|
||||
struct HMapBucket;
|
||||
struct HMapHeader;
|
||||
|
||||
/// This class represents an Apple concept known as a 'header map'. To the
|
||||
/// #include file resolution process, it basically acts like a directory of
|
||||
/// symlinks to files. Its advantages are that it is dense and more efficient
|
||||
/// to create and process than a directory of symlinks.
|
||||
class HeaderMap {
|
||||
HeaderMap(const HeaderMap&); // DO NOT IMPLEMENT
|
||||
void operator=(const HeaderMap&); // DO NOT IMPLEMENT
|
||||
|
||||
const llvm::MemoryBuffer *FileBuffer;
|
||||
bool NeedsBSwap;
|
||||
|
||||
HeaderMap(const llvm::MemoryBuffer *File, bool BSwap)
|
||||
: FileBuffer(File), NeedsBSwap(BSwap) {
|
||||
}
|
||||
public:
|
||||
~HeaderMap();
|
||||
|
||||
/// HeaderMap::Create - This attempts to load the specified file as a header
|
||||
/// map. If it doesn't look like a HeaderMap, it gives up and returns null.
|
||||
static const HeaderMap *Create(const FileEntry *FE);
|
||||
|
||||
/// LookupFile - Check to see if the specified relative filename is located in
|
||||
/// this HeaderMap. If so, open it and return its FileEntry.
|
||||
const FileEntry *LookupFile(const char *FilenameStart,const char *FilenameEnd,
|
||||
FileManager &FM) const;
|
||||
|
||||
/// getFileName - Return the filename of the headermap.
|
||||
const char *getFileName() const;
|
||||
|
||||
/// dump - Print the contents of this headermap to stderr.
|
||||
void dump() const;
|
||||
|
||||
private:
|
||||
unsigned getEndianAdjustedWord(unsigned X) const;
|
||||
const HMapHeader &getHeader() const;
|
||||
HMapBucket getBucket(unsigned BucketNo) const;
|
||||
const char *getString(unsigned StrTabIdx) const;
|
||||
};
|
||||
|
||||
} // end namespace clang.
|
||||
|
||||
#endif
|
||||
@@ -1,204 +0,0 @@
|
||||
//===--- HeaderSearch.h - Resolve Header File Locations ---------*- 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 HeaderSearch interface.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_LEX_HEADERSEARCH_H
|
||||
#define LLVM_CLANG_LEX_HEADERSEARCH_H
|
||||
|
||||
#include "clang/Lex/DirectoryLookup.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include <vector>
|
||||
|
||||
namespace clang {
|
||||
class FileEntry;
|
||||
class FileManager;
|
||||
class IdentifierInfo;
|
||||
|
||||
|
||||
/// HeaderSearch - This class encapsulates the information needed to find the
|
||||
/// file referenced by a #include or #include_next, (sub-)framework lookup, etc.
|
||||
class HeaderSearch {
|
||||
FileManager &FileMgr;
|
||||
|
||||
/// #include search path information. Requests for #include "x" search the
|
||||
/// directory of the #including file first, then each directory in SearchDirs
|
||||
/// consequtively. Requests for <x> search the current dir first, then each
|
||||
/// directory in SearchDirs, starting at SystemDirIdx, consequtively. If
|
||||
/// NoCurDirSearch is true, then the check for the file in the current
|
||||
/// directory is supressed.
|
||||
std::vector<DirectoryLookup> SearchDirs;
|
||||
unsigned SystemDirIdx;
|
||||
bool NoCurDirSearch;
|
||||
|
||||
/// PreFileInfo - The preprocessor keeps track of this information for each
|
||||
/// file that is #included.
|
||||
struct PerFileInfo {
|
||||
/// isImport - True if this is a #import'd or #pragma once file.
|
||||
bool isImport : 1;
|
||||
|
||||
// NOTE: VC++ treats enums as signed, avoid using DirectoryLookup::DirType
|
||||
/// DirInfo - Keep track of whether this is a system header, and if so,
|
||||
/// whether it is C++ clean or not. This can be set by the include paths or
|
||||
/// by #pragma gcc system_header.
|
||||
unsigned DirInfo : 2;
|
||||
|
||||
/// NumIncludes - This is the number of times the file has been included
|
||||
/// already.
|
||||
unsigned short NumIncludes;
|
||||
|
||||
/// ControllingMacro - If this file has a #ifndef XXX (or equivalent) guard
|
||||
/// that protects the entire contents of the file, this is the identifier
|
||||
/// for the macro that controls whether or not it has any effect.
|
||||
const IdentifierInfo *ControllingMacro;
|
||||
|
||||
PerFileInfo() : isImport(false), DirInfo(DirectoryLookup::NormalHeaderDir),
|
||||
NumIncludes(0), ControllingMacro(0) {}
|
||||
};
|
||||
|
||||
/// FileInfo - This contains all of the preprocessor-specific data about files
|
||||
/// that are included. The vector is indexed by the FileEntry's UID.
|
||||
///
|
||||
std::vector<PerFileInfo> FileInfo;
|
||||
|
||||
/// LookupFileCache - This is keeps track of each lookup performed by
|
||||
/// LookupFile. The first part of the value is the starting index in
|
||||
/// SearchDirs that the cached search was performed from. If there is a hit
|
||||
/// and this value doesn't match the current query, the cache has to be
|
||||
/// ignored. The second value is the entry in SearchDirs that satisfied the
|
||||
/// query.
|
||||
llvm::StringMap<std::pair<unsigned, unsigned> > LookupFileCache;
|
||||
|
||||
|
||||
/// FrameworkMap - This is a collection mapping a framework or subframework
|
||||
/// name like "Carbon" to the Carbon.framework directory.
|
||||
llvm::StringMap<const DirectoryEntry *> FrameworkMap;
|
||||
|
||||
/// HeaderMaps - This is a mapping from FileEntry -> HeaderMap, uniquing
|
||||
/// headermaps. This vector owns the headermap.
|
||||
std::vector<std::pair<const FileEntry*, const HeaderMap*> > HeaderMaps;
|
||||
|
||||
// Various statistics we track for performance analysis.
|
||||
unsigned NumIncluded;
|
||||
unsigned NumMultiIncludeFileOptzn;
|
||||
unsigned NumFrameworkLookups, NumSubFrameworkLookups;
|
||||
|
||||
// HeaderSearch doesn't support default or copy construction.
|
||||
explicit HeaderSearch();
|
||||
explicit HeaderSearch(const HeaderSearch&);
|
||||
void operator=(const HeaderSearch&);
|
||||
public:
|
||||
HeaderSearch(FileManager &FM);
|
||||
~HeaderSearch();
|
||||
|
||||
FileManager &getFileMgr() const { return FileMgr; }
|
||||
|
||||
/// SetSearchPaths - Interface for setting the file search paths.
|
||||
///
|
||||
void SetSearchPaths(const std::vector<DirectoryLookup> &dirs,
|
||||
unsigned systemDirIdx, bool noCurDirSearch) {
|
||||
SearchDirs = dirs;
|
||||
SystemDirIdx = systemDirIdx;
|
||||
NoCurDirSearch = noCurDirSearch;
|
||||
//LookupFileCache.clear();
|
||||
}
|
||||
|
||||
/// ClearFileInfo - Forget everything we know about headers so far.
|
||||
void ClearFileInfo() {
|
||||
FileInfo.clear();
|
||||
}
|
||||
|
||||
/// LookupFile - Given a "foo" or <foo> reference, look up the indicated file,
|
||||
/// return null on failure. isAngled indicates whether the file reference is
|
||||
/// a <> reference. If successful, this returns 'UsedDir', the
|
||||
/// DirectoryLookup member the file was found in, or null if not applicable.
|
||||
/// If CurDir is non-null, the file was found in the specified directory
|
||||
/// search location. This is used to implement #include_next. CurFileEnt, if
|
||||
/// non-null, indicates where the #including file is, in case a relative
|
||||
/// search is needed.
|
||||
const FileEntry *LookupFile(const char *FilenameStart,
|
||||
const char *FilenameEnd, bool isAngled,
|
||||
const DirectoryLookup *FromDir,
|
||||
const DirectoryLookup *&CurDir,
|
||||
const FileEntry *CurFileEnt);
|
||||
|
||||
/// LookupSubframeworkHeader - Look up a subframework for the specified
|
||||
/// #include file. For example, if #include'ing <HIToolbox/HIToolbox.h> from
|
||||
/// within ".../Carbon.framework/Headers/Carbon.h", check to see if HIToolbox
|
||||
/// is a subframework within Carbon.framework. If so, return the FileEntry
|
||||
/// for the designated file, otherwise return null.
|
||||
const FileEntry *LookupSubframeworkHeader(const char *FilenameStart,
|
||||
const char *FilenameEnd,
|
||||
const FileEntry *RelativeFileEnt);
|
||||
|
||||
/// LookupFrameworkCache - Look up the specified framework name in our
|
||||
/// framework cache, returning the DirectoryEntry it is in if we know,
|
||||
/// otherwise, return null.
|
||||
const DirectoryEntry *&LookupFrameworkCache(const char *FWNameStart,
|
||||
const char *FWNameEnd) {
|
||||
return FrameworkMap.GetOrCreateValue(FWNameStart, FWNameEnd).getValue();
|
||||
}
|
||||
|
||||
/// ShouldEnterIncludeFile - Mark the specified file as a target of of a
|
||||
/// #include, #include_next, or #import directive. Return false if #including
|
||||
/// the file will have no effect or true if we should include it.
|
||||
bool ShouldEnterIncludeFile(const FileEntry *File, bool isImport);
|
||||
|
||||
|
||||
/// getFileDirFlavor - Return whether the specified file is a normal header,
|
||||
/// a system header, or a C++ friendly system header.
|
||||
DirectoryLookup::DirType getFileDirFlavor(const FileEntry *File) {
|
||||
return DirectoryLookup::DirType(getFileInfo(File).DirInfo);
|
||||
}
|
||||
|
||||
/// MarkFileIncludeOnce - Mark the specified file as a "once only" file, e.g.
|
||||
/// due to #pragma once.
|
||||
void MarkFileIncludeOnce(const FileEntry *File) {
|
||||
getFileInfo(File).isImport = true;
|
||||
}
|
||||
|
||||
/// MarkFileSystemHeader - Mark the specified fiel as a system header, e.g.
|
||||
/// due to #pragma GCC system_header.
|
||||
void MarkFileSystemHeader(const FileEntry *File) {
|
||||
getFileInfo(File).DirInfo = DirectoryLookup::SystemHeaderDir;
|
||||
}
|
||||
|
||||
/// IncrementIncludeCount - Increment the count for the number of times the
|
||||
/// specified FileEntry has been entered.
|
||||
void IncrementIncludeCount(const FileEntry *File) {
|
||||
++getFileInfo(File).NumIncludes;
|
||||
}
|
||||
|
||||
/// SetFileControllingMacro - Mark the specified file as having a controlling
|
||||
/// macro. This is used by the multiple-include optimization to eliminate
|
||||
/// no-op #includes.
|
||||
void SetFileControllingMacro(const FileEntry *File,
|
||||
const IdentifierInfo *ControllingMacro) {
|
||||
getFileInfo(File).ControllingMacro = ControllingMacro;
|
||||
}
|
||||
|
||||
/// CreateHeaderMap - This method returns a HeaderMap for the specified
|
||||
/// FileEntry, uniquing them through the the 'HeaderMaps' datastructure.
|
||||
const HeaderMap *CreateHeaderMap(const FileEntry *FE);
|
||||
|
||||
void IncrementFrameworkLookupCount() { ++NumFrameworkLookups; }
|
||||
|
||||
void PrintStats();
|
||||
private:
|
||||
|
||||
/// getFileInfo - Return the PerFileInfo structure for the specified
|
||||
/// FileEntry.
|
||||
PerFileInfo &getFileInfo(const FileEntry *FE);
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
@@ -1,383 +0,0 @@
|
||||
//===--- Lexer.h - C Language Family Lexer ----------------------*- 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 Lexer interface.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_LEXER_H
|
||||
#define LLVM_CLANG_LEXER_H
|
||||
|
||||
#include "clang/Lex/Token.h"
|
||||
#include "clang/Lex/MultipleIncludeOpt.h"
|
||||
#include "clang/Basic/LangOptions.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <cassert>
|
||||
|
||||
namespace clang {
|
||||
class Diagnostic;
|
||||
class SourceManager;
|
||||
class Preprocessor;
|
||||
|
||||
/// Lexer - This provides a simple interface that turns a text buffer into a
|
||||
/// stream of tokens. This provides no support for file reading or buffering,
|
||||
/// or buffering/seeking of tokens, only forward lexing is supported. It relies
|
||||
/// on the specified Preprocessor object to handle preprocessor directives, etc.
|
||||
class Lexer {
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Constant configuration values for this lexer.
|
||||
const char *BufferStart; // Start of the buffer.
|
||||
const char *BufferEnd; // End of the buffer.
|
||||
SourceLocation FileLoc; // Location for start of file.
|
||||
Preprocessor *PP; // Preprocessor object controlling lexing.
|
||||
LangOptions Features; // Features enabled by this language (cache).
|
||||
bool Is_PragmaLexer; // True if lexer for _Pragma handling.
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Context-specific lexing flags set by the preprocessor.
|
||||
//
|
||||
|
||||
/// ParsingPreprocessorDirective - This is true when parsing #XXX. This turns
|
||||
/// '\n' into a tok::eom token.
|
||||
bool ParsingPreprocessorDirective;
|
||||
|
||||
/// ParsingFilename - True after #include: this turns <xx> into a
|
||||
/// tok::angle_string_literal token.
|
||||
bool ParsingFilename;
|
||||
|
||||
/// LexingRawMode - True if in raw mode: This flag disables interpretation of
|
||||
/// tokens and is a far faster mode to lex in than non-raw-mode. This flag:
|
||||
/// 1. If EOF of the current lexer is found, the include stack isn't popped.
|
||||
/// 2. Identifier information is not looked up for identifier tokens. As an
|
||||
/// effect of this, implicit macro expansion is naturally disabled.
|
||||
/// 3. "#" tokens at the start of a line are treated as normal tokens, not
|
||||
/// implicitly transformed by the lexer.
|
||||
/// 4. All diagnostic messages are disabled, except for unterminated /*.
|
||||
/// 5. The only callback made into the preprocessor is to report a hard error
|
||||
/// on an unterminated '/*' comment.
|
||||
///
|
||||
/// Note that in raw mode that the PP pointer may be null.
|
||||
bool LexingRawMode;
|
||||
|
||||
/// KeepCommentMode - The lexer can optionally keep C & BCPL-style comments,
|
||||
/// and return them as tokens. This is used for -C and -CC modes.
|
||||
bool KeepCommentMode;
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Context that changes as the file is lexed.
|
||||
// NOTE: any state that mutates when in raw mode must have save/restore code
|
||||
// in Lexer::isNextPPTokenLParen.
|
||||
|
||||
// BufferPtr - Current pointer into the buffer. This is the next character
|
||||
// to be lexed.
|
||||
const char *BufferPtr;
|
||||
|
||||
// IsAtStartOfLine - True if the next lexed token should get the "start of
|
||||
// line" flag set on it.
|
||||
bool IsAtStartOfLine;
|
||||
|
||||
/// MIOpt - This is a state machine that detects the #ifndef-wrapping a file
|
||||
/// idiom for the multiple-include optimization.
|
||||
MultipleIncludeOpt MIOpt;
|
||||
|
||||
/// ConditionalStack - Information about the set of #if/#ifdef/#ifndef blocks
|
||||
/// we are currently in.
|
||||
std::vector<PPConditionalInfo> ConditionalStack;
|
||||
|
||||
Lexer(const Lexer&); // DO NOT IMPLEMENT
|
||||
void operator=(const Lexer&); // DO NOT IMPLEMENT
|
||||
friend class Preprocessor;
|
||||
public:
|
||||
|
||||
/// Lexer constructor - Create a new lexer object for the specified buffer
|
||||
/// with the specified preprocessor managing the lexing process. This lexer
|
||||
/// assumes that the associated file buffer and Preprocessor objects will
|
||||
/// outlive it, so it doesn't take ownership of either of them.
|
||||
Lexer(SourceLocation FileLoc, Preprocessor &PP,
|
||||
const char *BufStart = 0, const char *BufEnd = 0);
|
||||
|
||||
/// Lexer constructor - Create a new raw lexer object. This object is only
|
||||
/// suitable for calls to 'LexRawToken'. This lexer assumes that the
|
||||
/// associated file buffer will outlive it, so it doesn't take ownership of
|
||||
/// either of them.
|
||||
Lexer(SourceLocation FileLoc, const LangOptions &Features,
|
||||
const char *BufStart, const char *BufEnd);
|
||||
|
||||
/// getFeatures - Return the language features currently enabled. NOTE: this
|
||||
/// lexer modifies features as a file is parsed!
|
||||
const LangOptions &getFeatures() const { return Features; }
|
||||
|
||||
/// getFileLoc - Return the File Location for the file we are lexing out of.
|
||||
/// The physical location encodes the location where the characters come from,
|
||||
/// the virtual location encodes where we should *claim* the characters came
|
||||
/// from. Currently this is only used by _Pragma handling.
|
||||
SourceLocation getFileLoc() const { return FileLoc; }
|
||||
|
||||
/// Lex - Return the next token in the file. If this is the end of file, it
|
||||
/// return the tok::eof token. Return true if an error occurred and
|
||||
/// compilation should terminate, false if normal. This implicitly involves
|
||||
/// the preprocessor.
|
||||
void Lex(Token &Result) {
|
||||
// Start a new token.
|
||||
Result.startToken();
|
||||
|
||||
// NOTE, any changes here should also change code after calls to
|
||||
// Preprocessor::HandleDirective
|
||||
if (IsAtStartOfLine) {
|
||||
Result.setFlag(Token::StartOfLine);
|
||||
IsAtStartOfLine = false;
|
||||
}
|
||||
|
||||
// Get a token. Note that this may delete the current lexer if the end of
|
||||
// file is reached.
|
||||
LexTokenInternal(Result);
|
||||
}
|
||||
|
||||
/// LexRawToken - Switch the lexer to raw mode, lex a token into Result and
|
||||
/// switch it back. Return true if the 'next character to read' pointer
|
||||
/// points and the end of the lexer buffer, false otherwise.
|
||||
bool LexRawToken(Token &Result) {
|
||||
assert(!(PP && LexingRawMode) && "Already in raw mode!");
|
||||
LexingRawMode = true;
|
||||
Lex(Result);
|
||||
LexingRawMode = PP == 0;
|
||||
// Note that lexing to the end of the buffer doesn't implicitly delete the
|
||||
// lexer when in raw mode.
|
||||
return BufferPtr == BufferEnd;
|
||||
}
|
||||
|
||||
/// SetCommentRetentionMode - Change the comment retention mode of the lexer
|
||||
/// to the specified mode. This is really only useful when lexing in raw
|
||||
/// mode, because otherwise the lexer needs to manage this.
|
||||
void SetCommentRetentionState(bool Mode) {
|
||||
KeepCommentMode = Mode;
|
||||
}
|
||||
|
||||
/// ReadToEndOfLine - Read the rest of the current preprocessor line as an
|
||||
/// uninterpreted string. This switches the lexer out of directive mode.
|
||||
std::string ReadToEndOfLine();
|
||||
|
||||
|
||||
/// Diag - Forwarding function for diagnostics. This translate a source
|
||||
/// position in the current buffer into a SourceLocation object for rendering.
|
||||
void Diag(const char *Loc, unsigned DiagID,
|
||||
const std::string &Msg = std::string()) const;
|
||||
void Diag(SourceLocation Loc, unsigned DiagID,
|
||||
const std::string &Msg = std::string()) const;
|
||||
|
||||
/// getSourceLocation - Return a source location identifier for the specified
|
||||
/// offset in the current file.
|
||||
SourceLocation getSourceLocation(const char *Loc) const;
|
||||
|
||||
/// Stringify - Convert the specified string into a C string by escaping '\'
|
||||
/// and " characters. This does not add surrounding ""'s to the string.
|
||||
/// If Charify is true, this escapes the ' character instead of ".
|
||||
static std::string Stringify(const std::string &Str, bool Charify = false);
|
||||
|
||||
/// Stringify - Convert the specified string into a C string by escaping '\'
|
||||
/// and " characters. This does not add surrounding ""'s to the string.
|
||||
static void Stringify(llvm::SmallVectorImpl<char> &Str);
|
||||
|
||||
/// MeasureTokenLength - Relex the token at the specified location and return
|
||||
/// its length in bytes in the input file. If the token needs cleaning (e.g.
|
||||
/// includes a trigraph or an escaped newline) then this count includes bytes
|
||||
/// that are part of that.
|
||||
static unsigned MeasureTokenLength(SourceLocation Loc,
|
||||
const SourceManager &SM);
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Internal implementation interfaces.
|
||||
private:
|
||||
|
||||
/// LexTokenInternal - Internal interface to lex a preprocessing token. Called
|
||||
/// by Lex.
|
||||
///
|
||||
void LexTokenInternal(Token &Result);
|
||||
|
||||
/// FormTokenWithChars - When we lex a token, we have identified a span
|
||||
/// starting at BufferPtr, going to TokEnd that forms the token. This method
|
||||
/// takes that range and assigns it to the token as its location and size. In
|
||||
/// addition, since tokens cannot overlap, this also updates BufferPtr to be
|
||||
/// TokEnd.
|
||||
void FormTokenWithChars(Token &Result, const char *TokEnd) {
|
||||
Result.setLocation(getSourceLocation(BufferPtr));
|
||||
Result.setLength(TokEnd-BufferPtr);
|
||||
BufferPtr = TokEnd;
|
||||
}
|
||||
|
||||
/// isNextPPTokenLParen - Return 1 if the next unexpanded token will return a
|
||||
/// tok::l_paren token, 0 if it is something else and 2 if there are no more
|
||||
/// tokens in the buffer controlled by this lexer.
|
||||
unsigned isNextPPTokenLParen();
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Lexer character reading interfaces.
|
||||
public:
|
||||
|
||||
// This lexer is built on two interfaces for reading characters, both of which
|
||||
// automatically provide phase 1/2 translation. getAndAdvanceChar is used
|
||||
// when we know that we will be reading a character from the input buffer and
|
||||
// that this character will be part of the result token. This occurs in (f.e.)
|
||||
// string processing, because we know we need to read until we find the
|
||||
// closing '"' character.
|
||||
//
|
||||
// The second interface is the combination of PeekCharAndSize with
|
||||
// ConsumeChar. PeekCharAndSize reads a phase 1/2 translated character,
|
||||
// returning it and its size. If the lexer decides that this character is
|
||||
// part of the current token, it calls ConsumeChar on it. This two stage
|
||||
// approach allows us to emit diagnostics for characters (e.g. warnings about
|
||||
// trigraphs), knowing that they only are emitted if the character is
|
||||
// consumed.
|
||||
|
||||
/// isObviouslySimpleCharacter - Return true if the specified character is
|
||||
/// obviously the same in translation phase 1 and translation phase 3. This
|
||||
/// can return false for characters that end up being the same, but it will
|
||||
/// never return true for something that needs to be mapped.
|
||||
static bool isObviouslySimpleCharacter(char C) {
|
||||
return C != '?' && C != '\\';
|
||||
}
|
||||
|
||||
/// getAndAdvanceChar - Read a single 'character' from the specified buffer,
|
||||
/// advance over it, and return it. This is tricky in several cases. Here we
|
||||
/// just handle the trivial case and fall-back to the non-inlined
|
||||
/// getCharAndSizeSlow method to handle the hard case.
|
||||
inline char getAndAdvanceChar(const char *&Ptr, Token &Tok) {
|
||||
// If this is not a trigraph and not a UCN or escaped newline, return
|
||||
// quickly.
|
||||
if (isObviouslySimpleCharacter(Ptr[0])) return *Ptr++;
|
||||
|
||||
unsigned Size = 0;
|
||||
char C = getCharAndSizeSlow(Ptr, Size, &Tok);
|
||||
Ptr += Size;
|
||||
return C;
|
||||
}
|
||||
|
||||
private:
|
||||
/// ConsumeChar - When a character (identified by PeekCharAndSize) is consumed
|
||||
/// and added to a given token, check to see if there are diagnostics that
|
||||
/// need to be emitted or flags that need to be set on the token. If so, do
|
||||
/// it.
|
||||
const char *ConsumeChar(const char *Ptr, unsigned Size, Token &Tok) {
|
||||
// Normal case, we consumed exactly one token. Just return it.
|
||||
if (Size == 1)
|
||||
return Ptr+Size;
|
||||
|
||||
// Otherwise, re-lex the character with a current token, allowing
|
||||
// diagnostics to be emitted and flags to be set.
|
||||
Size = 0;
|
||||
getCharAndSizeSlow(Ptr, Size, &Tok);
|
||||
return Ptr+Size;
|
||||
}
|
||||
|
||||
/// getCharAndSize - Peek a single 'character' from the specified buffer,
|
||||
/// get its size, and return it. This is tricky in several cases. Here we
|
||||
/// just handle the trivial case and fall-back to the non-inlined
|
||||
/// getCharAndSizeSlow method to handle the hard case.
|
||||
inline char getCharAndSize(const char *Ptr, unsigned &Size) {
|
||||
// If this is not a trigraph and not a UCN or escaped newline, return
|
||||
// quickly.
|
||||
if (isObviouslySimpleCharacter(Ptr[0])) {
|
||||
Size = 1;
|
||||
return *Ptr;
|
||||
}
|
||||
|
||||
Size = 0;
|
||||
return getCharAndSizeSlow(Ptr, Size);
|
||||
}
|
||||
|
||||
/// getCharAndSizeSlow - Handle the slow/uncommon case of the getCharAndSize
|
||||
/// method.
|
||||
char getCharAndSizeSlow(const char *Ptr, unsigned &Size, Token *Tok = 0);
|
||||
|
||||
/// getCharAndSizeNoWarn - Like the getCharAndSize method, but does not ever
|
||||
/// emit a warning.
|
||||
static inline char getCharAndSizeNoWarn(const char *Ptr, unsigned &Size,
|
||||
const LangOptions &Features) {
|
||||
// If this is not a trigraph and not a UCN or escaped newline, return
|
||||
// quickly.
|
||||
if (isObviouslySimpleCharacter(Ptr[0])) {
|
||||
Size = 1;
|
||||
return *Ptr;
|
||||
}
|
||||
|
||||
Size = 0;
|
||||
return getCharAndSizeSlowNoWarn(Ptr, Size, Features);
|
||||
}
|
||||
|
||||
/// getCharAndSizeSlowNoWarn - Same as getCharAndSizeSlow, but never emits a
|
||||
/// diagnostic.
|
||||
static char getCharAndSizeSlowNoWarn(const char *Ptr, unsigned &Size,
|
||||
const LangOptions &Features);
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// #if directive handling.
|
||||
|
||||
/// pushConditionalLevel - When we enter a #if directive, this keeps track of
|
||||
/// what we are currently in for diagnostic emission (e.g. #if with missing
|
||||
/// #endif).
|
||||
void pushConditionalLevel(SourceLocation DirectiveStart, bool WasSkipping,
|
||||
bool FoundNonSkip, bool FoundElse) {
|
||||
PPConditionalInfo CI;
|
||||
CI.IfLoc = DirectiveStart;
|
||||
CI.WasSkipping = WasSkipping;
|
||||
CI.FoundNonSkip = FoundNonSkip;
|
||||
CI.FoundElse = FoundElse;
|
||||
ConditionalStack.push_back(CI);
|
||||
}
|
||||
void pushConditionalLevel(const PPConditionalInfo &CI) {
|
||||
ConditionalStack.push_back(CI);
|
||||
}
|
||||
|
||||
/// popConditionalLevel - Remove an entry off the top of the conditional
|
||||
/// stack, returning information about it. If the conditional stack is empty,
|
||||
/// this returns true and does not fill in the arguments.
|
||||
bool popConditionalLevel(PPConditionalInfo &CI) {
|
||||
if (ConditionalStack.empty()) return true;
|
||||
CI = ConditionalStack.back();
|
||||
ConditionalStack.pop_back();
|
||||
return false;
|
||||
}
|
||||
|
||||
/// peekConditionalLevel - Return the top of the conditional stack. This
|
||||
/// requires that there be a conditional active.
|
||||
PPConditionalInfo &peekConditionalLevel() {
|
||||
assert(!ConditionalStack.empty() && "No conditionals active!");
|
||||
return ConditionalStack.back();
|
||||
}
|
||||
|
||||
unsigned getConditionalStackDepth() const { return ConditionalStack.size(); }
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Other lexer functions.
|
||||
|
||||
// Helper functions to lex the remainder of a token of the specific type.
|
||||
void LexIdentifier (Token &Result, const char *CurPtr);
|
||||
void LexNumericConstant (Token &Result, const char *CurPtr);
|
||||
void LexStringLiteral (Token &Result, const char *CurPtr,bool Wide);
|
||||
void LexAngledStringLiteral(Token &Result, const char *CurPtr);
|
||||
void LexCharConstant (Token &Result, const char *CurPtr);
|
||||
bool LexEndOfFile (Token &Result, const char *CurPtr);
|
||||
|
||||
void SkipWhitespace (Token &Result, const char *CurPtr);
|
||||
bool SkipBCPLComment (Token &Result, const char *CurPtr);
|
||||
bool SkipBlockComment (Token &Result, const char *CurPtr);
|
||||
bool SaveBCPLComment (Token &Result, const char *CurPtr);
|
||||
|
||||
/// LexIncludeFilename - After the preprocessor has parsed a #include, lex and
|
||||
/// (potentially) macro expand the filename. If the sequence parsed is not
|
||||
/// lexically legal, emit a diagnostic and return a result EOM token.
|
||||
void LexIncludeFilename(Token &Result);
|
||||
};
|
||||
|
||||
|
||||
} // 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