diff options
Diffstat (limited to 'lib/Frontend')
-rw-r--r-- | lib/Frontend/ASTConsumers.cpp | 8 | ||||
-rw-r--r-- | lib/Frontend/ASTUnit.cpp | 159 | ||||
-rw-r--r-- | lib/Frontend/CMakeLists.txt | 4 | ||||
-rw-r--r-- | lib/Frontend/DeclXML.cpp | 161 | ||||
-rw-r--r-- | lib/Frontend/DocumentXML.cpp | 348 | ||||
-rw-r--r-- | lib/Frontend/InitHeaderSearch.cpp | 6 | ||||
-rw-r--r-- | lib/Frontend/InitPreprocessor.cpp | 6 | ||||
-rw-r--r-- | lib/Frontend/PCHReader.cpp | 814 | ||||
-rw-r--r-- | lib/Frontend/PCHReaderDecl.cpp | 4 | ||||
-rw-r--r-- | lib/Frontend/PCHReaderStmt.cpp | 1 | ||||
-rw-r--r-- | lib/Frontend/PCHWriter.cpp | 10 | ||||
-rw-r--r-- | lib/Frontend/PCHWriterDecl.cpp | 6 | ||||
-rw-r--r-- | lib/Frontend/PCHWriterStmt.cpp | 1 | ||||
-rw-r--r-- | lib/Frontend/PrintPreprocessedOutput.cpp | 35 | ||||
-rw-r--r-- | lib/Frontend/RewriteBlocks.cpp | 2 | ||||
-rw-r--r-- | lib/Frontend/RewriteObjC.cpp | 2 | ||||
-rw-r--r-- | lib/Frontend/StmtXML.cpp | 100 | ||||
-rw-r--r-- | lib/Frontend/TextDiagnosticPrinter.cpp | 13 | ||||
-rw-r--r-- | lib/Frontend/TypeXML.cpp | 127 |
19 files changed, 1142 insertions, 665 deletions
diff --git a/lib/Frontend/ASTConsumers.cpp b/lib/Frontend/ASTConsumers.cpp index 11c9251..5844be8 100644 --- a/lib/Frontend/ASTConsumers.cpp +++ b/lib/Frontend/ASTConsumers.cpp @@ -243,7 +243,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC, } case Decl::CXXMethod: { const CXXMethodDecl* D = cast<CXXMethodDecl>(DC); - if (D->isOutOfLineDefinition()) + if (D->isOutOfLine()) Out << "[c++ method] "; else if (D->isImplicit()) Out << "(c++ method) "; @@ -273,7 +273,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC, } case Decl::CXXConstructor: { const CXXConstructorDecl* D = cast<CXXConstructorDecl>(DC); - if (D->isOutOfLineDefinition()) + if (D->isOutOfLine()) Out << "[c++ ctor] "; else if (D->isImplicit()) Out << "(c++ ctor) "; @@ -302,7 +302,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC, } case Decl::CXXDestructor: { const CXXDestructorDecl* D = cast<CXXDestructorDecl>(DC); - if (D->isOutOfLineDefinition()) + if (D->isOutOfLine()) Out << "[c++ dtor] "; else if (D->isImplicit()) Out << "(c++ dtor) "; @@ -318,7 +318,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC, } case Decl::CXXConversion: { const CXXConversionDecl* D = cast<CXXConversionDecl>(DC); - if (D->isOutOfLineDefinition()) + if (D->isOutOfLine()) Out << "[c++ conversion] "; else if (D->isImplicit()) Out << "(c++ conversion) "; diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp new file mode 100644 index 0000000..a7fbcda --- /dev/null +++ b/lib/Frontend/ASTUnit.cpp @@ -0,0 +1,159 @@ +//===--- ASTUnit.cpp - ASTUnit utility ------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// ASTUnit Implementation. +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/ASTUnit.h" +#include "clang/Frontend/PCHReader.h" +#include "clang/Frontend/TextDiagnosticBuffer.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/DeclVisitor.h" +#include "clang/AST/StmtVisitor.h" +#include "clang/Lex/HeaderSearch.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/Diagnostic.h" +#include "llvm/Support/Compiler.h" + +using namespace clang; + +ASTUnit::ASTUnit() { } +ASTUnit::~ASTUnit() { } + +namespace { + +/// \brief Gathers information from PCHReader that will be used to initialize +/// a Preprocessor. +class VISIBILITY_HIDDEN PCHInfoCollector : public PCHReaderListener { + LangOptions &LangOpt; + HeaderSearch &HSI; + std::string &TargetTriple; + std::string &Predefines; + unsigned &Counter; + + unsigned NumHeaderInfos; + +public: + PCHInfoCollector(LangOptions &LangOpt, HeaderSearch &HSI, + std::string &TargetTriple, std::string &Predefines, + unsigned &Counter) + : LangOpt(LangOpt), HSI(HSI), TargetTriple(TargetTriple), + Predefines(Predefines), Counter(Counter), NumHeaderInfos(0) {} + + virtual bool ReadLanguageOptions(const LangOptions &LangOpts) { + LangOpt = LangOpts; + return false; + } + + virtual bool ReadTargetTriple(const std::string &Triple) { + TargetTriple = Triple; + return false; + } + + virtual bool ReadPredefinesBuffer(const char *PCHPredef, + unsigned PCHPredefLen, + FileID PCHBufferID, + std::string &SuggestedPredefines) { + Predefines = PCHPredef; + return false; + } + + virtual void ReadHeaderFileInfo(const HeaderFileInfo &HFI) { + HSI.setHeaderFileInfoForUID(HFI, NumHeaderInfos++); + } + + virtual void ReadCounter(unsigned Value) { + Counter = Value; + } +}; + +} // anonymous namespace + + +ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename, + FileManager &FileMgr, + std::string *ErrMsg) { + + llvm::OwningPtr<ASTUnit> AST(new ASTUnit()); + + AST->DiagClient.reset(new TextDiagnosticBuffer()); + AST->Diags.reset(new Diagnostic(AST->DiagClient.get())); + + AST->HeaderInfo.reset(new HeaderSearch(FileMgr)); + AST->SourceMgr.reset(new SourceManager()); + + Diagnostic &Diags = *AST->Diags.get(); + SourceManager &SourceMgr = *AST->SourceMgr.get(); + + // Gather Info for preprocessor construction later on. + + LangOptions LangInfo; + HeaderSearch &HeaderInfo = *AST->HeaderInfo.get(); + std::string TargetTriple; + std::string Predefines; + unsigned Counter; + + llvm::OwningPtr<PCHReader> Reader; + llvm::OwningPtr<ExternalASTSource> Source; + + Reader.reset(new PCHReader(SourceMgr, FileMgr, Diags)); + Reader->setListener(new PCHInfoCollector(LangInfo, HeaderInfo, TargetTriple, + Predefines, Counter)); + + switch (Reader->ReadPCH(Filename)) { + case PCHReader::Success: + break; + + case PCHReader::Failure: + // Unrecoverable failure: don't even try to process the input + // file. + if (ErrMsg) + *ErrMsg = "Could not load PCH file"; + return NULL; + + case PCHReader::IgnorePCH: + assert(0 && "Is there a validation that should not have happened ?"); + } + + // PCH loaded successfully. Now create the preprocessor. + + // Get information about the target being compiled for. + AST->Target.reset(TargetInfo::CreateTargetInfo(TargetTriple)); + AST->PP.reset(new Preprocessor(Diags, LangInfo, *AST->Target.get(), + SourceMgr, HeaderInfo)); + Preprocessor &PP = *AST->PP.get(); + + PP.setPredefines(Predefines); + PP.setCounterValue(Counter); + Reader->setPreprocessor(PP); + + // Create and initialize the ASTContext. + + AST->Ctx.reset(new ASTContext(LangInfo, + SourceMgr, + *AST->Target.get(), + PP.getIdentifierTable(), + PP.getSelectorTable(), + PP.getBuiltinInfo(), + /* FreeMemory = */ true, + /* size_reserve = */0)); + ASTContext &Context = *AST->Ctx.get(); + + Reader->InitializeContext(Context); + + // Attach the PCH reader to the AST context as an external AST + // source, so that declarations will be deserialized from the + // PCH file as needed. + Source.reset(Reader.take()); + Context.setExternalSource(Source); + + return AST.take(); +} diff --git a/lib/Frontend/CMakeLists.txt b/lib/Frontend/CMakeLists.txt index 649f9da..330b4db 100644 --- a/lib/Frontend/CMakeLists.txt +++ b/lib/Frontend/CMakeLists.txt @@ -5,6 +5,7 @@ add_clang_library(clangFrontend ASTConsumers.cpp Backend.cpp CacheTokens.cpp + DeclXML.cpp DependencyFile.cpp DiagChecker.cpp DocumentXML.cpp @@ -31,5 +32,8 @@ add_clang_library(clangFrontend StmtXML.cpp TextDiagnosticBuffer.cpp TextDiagnosticPrinter.cpp + TypeXML.cpp Warnings.cpp ) + +add_dependencies(clangSema ClangDiagnosticFrontend) diff --git a/lib/Frontend/DeclXML.cpp b/lib/Frontend/DeclXML.cpp new file mode 100644 index 0000000..5c21999 --- /dev/null +++ b/lib/Frontend/DeclXML.cpp @@ -0,0 +1,161 @@ +//===--- DeclXML.cpp - XML implementation for Decl ASTs -------------------===// +// +// 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 XML document class, which provides the means to +// dump out the AST in a XML form that exposes type details and other fields. +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/DocumentXML.h" +#include "clang/AST/DeclVisitor.h" +#include "clang/AST/Expr.h" + +namespace clang { + +//--------------------------------------------------------- +class DocumentXML::DeclPrinter : public DeclVisitor<DocumentXML::DeclPrinter> +{ + DocumentXML& Doc; + + void addSubNodes(FunctionDecl* FD) + { + for (unsigned i = 0, e = FD->getNumParams(); i != e; ++i) + { + Visit(FD->getParamDecl(i)); + Doc.toParent(); + } + } + + void addSubNodes(RecordDecl* RD) + { + for (RecordDecl::field_iterator i = RD->field_begin(*Doc.Ctx), e = RD->field_end(*Doc.Ctx); i != e; ++i) + { + Visit(*i); + Doc.toParent(); + } + } + + void addSubNodes(EnumDecl* ED) + { + for (EnumDecl::enumerator_iterator i = ED->enumerator_begin(*Doc.Ctx), e = ED->enumerator_end(*Doc.Ctx); i != e; ++i) + { + Visit(*i); + Doc.toParent(); + } + } + + void addSubNodes(EnumConstantDecl* ECD) + { + if (ECD->getInitExpr()) + { + Doc.PrintStmt(ECD->getInitExpr()); + } + } + + void addSubNodes(FieldDecl* FdD) + { + if (FdD->isBitField()) + { + Doc.PrintStmt(FdD->getBitWidth()); + } + } + + void addSubNodes(VarDecl* V) + { + if (V->getInit()) + { + Doc.PrintStmt(V->getInit()); + } + } + + void addSubNodes(ParmVarDecl* argDecl) + { + if (argDecl->getDefaultArg()) + { + Doc.PrintStmt(argDecl->getDefaultArg()); + } + } + + void addSpecialAttribute(const char* pName, EnumDecl* ED) + { + const QualType& enumType = ED->getIntegerType(); + if (!enumType.isNull()) + { + Doc.addAttribute(pName, enumType); + } + } + + void addIdAttribute(LinkageSpecDecl* ED) + { + Doc.addAttribute("id", ED); + } + + void addIdAttribute(NamedDecl* ND) + { + Doc.addAttribute("id", ND); + } + +public: + DeclPrinter(DocumentXML& doc) : Doc(doc) {} + +#define NODE_XML( CLASS, NAME ) \ + void Visit##CLASS(CLASS* T) \ + { \ + Doc.addSubNode(NAME); + +#define ID_ATTRIBUTE_XML addIdAttribute(T); +#define ATTRIBUTE_XML( FN, NAME ) Doc.addAttribute(NAME, T->FN); +#define ATTRIBUTE_OPT_XML( FN, NAME ) Doc.addAttributeOptional(NAME, T->FN); +#define ATTRIBUTE_FILE_LOCATION_XML Doc.addLocation(T->getLocation()); +#define ATTRIBUTE_SPECIAL_XML( FN, NAME ) addSpecialAttribute(NAME, T); + +#define ATTRIBUTE_ENUM_XML( FN, NAME ) \ + { \ + const char* pAttributeName = NAME; \ + const bool optional = false; \ + switch (T->FN) { \ + default: assert(0 && "unknown enum value"); + +#define ATTRIBUTE_ENUM_OPT_XML( FN, NAME ) \ + { \ + const char* pAttributeName = NAME; \ + const bool optional = true; \ + switch (T->FN) { \ + default: assert(0 && "unknown enum value"); + +#define ENUM_XML( VALUE, NAME ) case VALUE: if ((!optional) || NAME[0]) Doc.addAttribute(pAttributeName, NAME); break; +#define END_ENUM_XML } } +#define END_NODE_XML } + +#define SUB_NODE_XML( CLASS ) addSubNodes(T); +#define SUB_NODE_SEQUENCE_XML( CLASS ) addSubNodes(T); +#define SUB_NODE_OPT_XML( CLASS ) addSubNodes(T); + +#include "clang/Frontend/DeclXML.def" +}; + + +//--------------------------------------------------------- +void DocumentXML::writeDeclToXML(Decl *D) +{ + DeclPrinter(*this).Visit(D); + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) + { + if (Stmt *Body = FD->getBody(*Ctx)) { + addSubNode("Body"); + PrintStmt(Body); + toParent(); + } + } + toParent(); +} + +//--------------------------------------------------------- +} // NS clang + diff --git a/lib/Frontend/DocumentXML.cpp b/lib/Frontend/DocumentXML.cpp index 7562d2a..19a7573 100644 --- a/lib/Frontend/DocumentXML.cpp +++ b/lib/Frontend/DocumentXML.cpp @@ -14,92 +14,66 @@ #include "clang/Frontend/DocumentXML.h" #include "clang/AST/Decl.h" -#include "clang/AST/DeclCXX.h" -#include "clang/AST/Expr.h" +#include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" #include "llvm/ADT/StringExtras.h" namespace clang { //--------------------------------------------------------- -struct DocumentXML::NodeXML -{ - std::string Name; - NodeXML* Parent; - - NodeXML(const std::string& name, NodeXML* parent) : - Name(name), - Parent(parent) - {} -}; - -//--------------------------------------------------------- DocumentXML::DocumentXML(const std::string& rootName, llvm::raw_ostream& out) : - Root(new NodeXML(rootName, 0)), - CurrentNode(Root), Out(out), Ctx(0), - CurrentIndent(0), HasCurrentNodeSubNodes(false) { + NodeStack.push(rootName); Out << "<?xml version=\"1.0\"?>\n<" << rootName; } //--------------------------------------------------------- -DocumentXML::~DocumentXML() -{ - assert(CurrentNode == Root && "not completely backtracked"); - delete Root; -} - -//--------------------------------------------------------- DocumentXML& DocumentXML::addSubNode(const std::string& name) { if (!HasCurrentNodeSubNodes) { Out << ">\n"; } - CurrentNode = new NodeXML(name, CurrentNode); + NodeStack.push(name); HasCurrentNodeSubNodes = false; - CurrentIndent += 2; Indent(); - Out << "<" << CurrentNode->Name; + Out << "<" << NodeStack.top(); return *this; } //--------------------------------------------------------- void DocumentXML::Indent() { - for (int i = 0; i < CurrentIndent; ++i) + for (size_t i = 0, e = (NodeStack.size() - 1) * 2; i < e; ++i) Out << ' '; } //--------------------------------------------------------- DocumentXML& DocumentXML::toParent() { - assert(CurrentNode != Root && "to much backtracking"); + assert(NodeStack.size() > 1 && "to much backtracking"); if (HasCurrentNodeSubNodes) { Indent(); - Out << "</" << CurrentNode->Name << ">\n"; + Out << "</" << NodeStack.top() << ">\n"; } else { Out << "/>\n"; } - NodeXML* NodeToDelete = CurrentNode; - CurrentNode = CurrentNode->Parent; - delete NodeToDelete; + NodeStack.pop(); HasCurrentNodeSubNodes = true; - CurrentIndent -= 2; return *this; } //--------------------------------------------------------- namespace { -enum tIdType { ID_NORMAL, ID_FILE, ID_LAST }; +enum tIdType { ID_NORMAL, ID_FILE, ID_LABEL, ID_LAST }; unsigned getNewId(tIdType idType) { @@ -110,7 +84,7 @@ unsigned getNewId(tIdType idType) //--------------------------------------------------------- inline std::string getPrefixedId(unsigned uId, tIdType idType) { - static const char idPrefix[ID_LAST] = { '_', 'f' }; + static const char idPrefix[ID_LAST] = { '_', 'f', 'l' }; char buffer[20]; char* BufPtr = llvm::utohex_buffer(uId, buffer + 20); *--BufPtr = idPrefix[idType]; @@ -132,6 +106,7 @@ bool addToMap(T& idMap, const V& value, tIdType idType = ID_NORMAL) } // anon NS + //--------------------------------------------------------- std::string DocumentXML::escapeString(const char* pStr, std::string::size_type len) { @@ -170,7 +145,7 @@ std::string DocumentXML::escapeString(const char* pStr, std::string::size_type l //--------------------------------------------------------- void DocumentXML::finalize() { - assert(CurrentNode == Root && "not completely backtracked"); + assert(NodeStack.size() == 1 && "not completely backtracked"); addSubNode("ReferenceSection"); addSubNode("Types"); @@ -179,71 +154,15 @@ void DocumentXML::finalize() { if (i->first.getCVRQualifiers() != 0) { - addSubNode("CvQualifiedType"); + writeTypeToXML(i->first); addAttribute("id", getPrefixedId(i->second, ID_NORMAL)); - addAttribute("type", getPrefixedId(BasicTypes[i->first.getTypePtr()], ID_NORMAL)); - if (i->first.isConstQualified()) addAttribute("const", "1"); - if (i->first.isVolatileQualified()) addAttribute("volatile", "1"); - if (i->first.isRestrictQualified()) addAttribute("restrict", "1"); toParent(); } } for (XML::IdMap<const Type*>::iterator i = BasicTypes.begin(), e = BasicTypes.end(); i != e; ++i) { - // don't use the get methods as they strip of typedef infos - if (const BuiltinType *BT = dyn_cast<BuiltinType>(i->first)) { - addSubNode("FundamentalType"); - addAttribute("name", BT->getName(Ctx->getLangOptions().CPlusPlus)); - } - else if (const PointerType *PT = dyn_cast<PointerType>(i->first)) { - addSubNode("PointerType"); - addTypeAttribute(PT->getPointeeType()); - } - else if (dyn_cast<FunctionType>(i->first) != 0) { - addSubNode("FunctionType"); - } - else if (const ReferenceType *RT = dyn_cast<ReferenceType>(i->first)) { - addSubNode("ReferenceType"); - addTypeAttribute(RT->getPointeeType()); - } - else if (const TypedefType * TT = dyn_cast<TypedefType>(i->first)) { - addSubNode("Typedef"); - addAttribute("name", TT->getDecl()->getNameAsString()); - addTypeAttribute(TT->getDecl()->getUnderlyingType()); - addContextAttribute(TT->getDecl()->getDeclContext()); - } - else if (const QualifiedNameType *QT = dyn_cast<QualifiedNameType>(i->first)) { - addSubNode("QualifiedNameType"); - addTypeAttribute(QT->getNamedType()); - } - else if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(i->first)) { - addSubNode("ArrayType"); - addAttribute("min", 0); - addAttribute("max", (CAT->getSize() - 1).toString(10, false)); - addTypeAttribute(CAT->getElementType()); - } - else if (const VariableArrayType *VAT = dyn_cast<VariableArrayType>(i->first)) { - addSubNode("VariableArrayType"); - addTypeAttribute(VAT->getElementType()); - } - else if (const TagType *RET = dyn_cast<TagType>(i->first)) { - const TagDecl *tagDecl = RET->getDecl(); - std::string tagKind = tagDecl->getKindName(); - tagKind[0] = std::toupper(tagKind[0]); - addSubNode(tagKind); - addAttribute("name", tagDecl->getNameAsString()); - addContextAttribute(tagDecl->getDeclContext()); - } - else if (const VectorType* VT = dyn_cast<VectorType>(i->first)) { - addSubNode("VectorType"); - addTypeAttribute(VT->getElementType()); - addAttribute("num_elements", VT->getNumElements()); - } - else - { - addSubNode("FIXMEType"); - } + writeTypeToXML(i->first); addAttribute("id", getPrefixedId(i->second, ID_NORMAL)); toParent(); } @@ -267,7 +186,7 @@ void DocumentXML::finalize() if (const DeclContext* parent = i->first->getParent()) { - addContextAttribute(parent); + addAttribute("context", parent); } toParent(); } @@ -285,21 +204,21 @@ void DocumentXML::finalize() toParent().toParent(); // write the root closing node (which has always subnodes) - Out << "</" << CurrentNode->Name << ">\n"; + Out << "</" << NodeStack.top() << ">\n"; } //--------------------------------------------------------- -void DocumentXML::addTypeAttribute(const QualType& pType) +void DocumentXML::addAttribute(const char* pAttributeName, const QualType& pType) { addTypeRecursively(pType); - addAttribute("type", getPrefixedId(Types[pType], ID_NORMAL)); + addAttribute(pAttributeName, getPrefixedId(Types[pType], ID_NORMAL)); } //--------------------------------------------------------- -void DocumentXML::addTypeIdAttribute(const Type* pType) +void DocumentXML::addPtrAttribute(const char* pAttributeName, const Type* pType) { - addBasicTypeRecursively(pType); - addAttribute("id", getPrefixedId(BasicTypes[pType], ID_NORMAL)); + addTypeRecursively(pType); + addAttribute(pAttributeName, getPrefixedId(BasicTypes[pType], ID_NORMAL)); } //--------------------------------------------------------- @@ -307,7 +226,7 @@ void DocumentXML::addTypeRecursively(const QualType& pType) { if (addToMap(Types, pType)) { - addBasicTypeRecursively(pType.getTypePtr()); + addTypeRecursively(pType.getTypePtr()); // beautifier: a non-qualified type shall be transparent if (pType.getCVRQualifiers() == 0) { @@ -317,43 +236,49 @@ void DocumentXML::addTypeRecursively(const QualType& pType) } //--------------------------------------------------------- -void DocumentXML::addBasicTypeRecursively(const Type* pType) +void DocumentXML::addTypeRecursively(const Type* pType) { if (addToMap(BasicTypes, pType)) { - if (const PointerType *PT = dyn_cast<PointerType>(pType)) { - addTypeRecursively(PT->getPointeeType()); - } - else if (const ReferenceType *RT = dyn_cast<ReferenceType>(pType)) { - addTypeRecursively(RT->getPointeeType()); - } - else if (const TypedefType *TT = dyn_cast<TypedefType>(pType)) { - addTypeRecursively(TT->getDecl()->getUnderlyingType()); - addContextsRecursively(TT->getDecl()->getDeclContext()); - } - else if (const QualifiedNameType *QT = dyn_cast<QualifiedNameType>(pType)) { - addTypeRecursively(QT->getNamedType()); - // FIXME: what to do with NestedNameSpecifier or shall this type be transparent? - } - else if (const ArrayType *AT = dyn_cast<ArrayType>(pType)) { - addTypeRecursively(AT->getElementType()); - // FIXME: doesn't work in the immediate streaming approach - /*if (const VariableArrayType *VAT = dyn_cast<VariableArrayType>(AT)) - { - addSubNode("VariableArraySizeExpression"); - PrintStmt(VAT->getSizeExpr()); - toParent(); - }*/ + addParentTypes(pType); +/* + // FIXME: doesn't work in the immediate streaming approach + if (const VariableArrayType *VAT = dyn_cast<VariableArrayType>(pType)) + { + addSubNode("VariableArraySizeExpression"); + PrintStmt(VAT->getSizeExpr()); + toParent(); } +*/ } } //--------------------------------------------------------- -void DocumentXML::addContextAttribute(const DeclContext *DC, tContextUsage usage) +void DocumentXML::addPtrAttribute(const char* pName, const DeclContext* DC) { addContextsRecursively(DC); - const char* pAttributeTags[2] = { "context", "id" }; - addAttribute(pAttributeTags[usage], getPrefixedId(Contexts[DC], ID_NORMAL)); + addAttribute(pName, getPrefixedId(Contexts[DC], ID_NORMAL)); +} + +//--------------------------------------------------------- +void DocumentXML::addPtrAttribute(const char* pAttributeName, const NamedDecl* D) +{ + if (const DeclContext* DC = dyn_cast<DeclContext>(D)) + { + addContextsRecursively(DC); + addAttribute(pAttributeName, getPrefixedId(Contexts[DC], ID_NORMAL)); + } + else + { + addToMap(Decls, D); + addAttribute(pAttributeName, getPrefixedId(Decls[D], ID_NORMAL)); + } +} + +//--------------------------------------------------------- +void DocumentXML::addPtrAttribute(const char* pName, const NamespaceDecl* D) +{ + addPtrAttribute(pName, static_cast<const DeclContext*>(D)); } //--------------------------------------------------------- @@ -372,6 +297,15 @@ void DocumentXML::addSourceFileAttribute(const std::string& fileName) addAttribute("file", getPrefixedId(SourceFiles[fileName], ID_FILE)); } + +//--------------------------------------------------------- +void DocumentXML::addPtrAttribute(const char* pName, const LabelStmt* L) +{ + addToMap(Labels, L, ID_LABEL); + addAttribute(pName, getPrefixedId(Labels[L], ID_LABEL)); +} + + //--------------------------------------------------------- PresumedLoc DocumentXML::addLocation(const SourceLocation& Loc) { @@ -417,161 +351,9 @@ void DocumentXML::addLocationRange(const SourceRange& R) } //--------------------------------------------------------- -void DocumentXML::PrintFunctionDecl(FunctionDecl *FD) -{ - switch (FD->getStorageClass()) { - default: assert(0 && "Unknown storage class"); - case FunctionDecl::None: break; - case FunctionDecl::Extern: addAttribute("storage_class", "extern"); break; - case FunctionDecl::Static: addAttribute("storage_class", "static"); break; - case FunctionDecl::PrivateExtern: addAttribute("storage_class", "__private_extern__"); break; - } - - if (FD->isInline()) - addAttribute("inline", "1"); - - const FunctionType *AFT = FD->getType()->getAsFunctionType(); - addTypeAttribute(AFT->getResultType()); - addBasicTypeRecursively(AFT); - - if (const FunctionProtoType *FT = dyn_cast<FunctionProtoType>(AFT)) { - addAttribute("num_args", FD->getNumParams()); - for (unsigned i = 0, e = FD->getNumParams(); i != e; ++i) { - addSubNode("Argument"); - ParmVarDecl *argDecl = FD->getParamDecl(i); - addAttribute("name", argDecl->getNameAsString()); - addTypeAttribute(FT->getArgType(i)); - addDeclIdAttribute(argDecl); - if (argDecl->getDefaultArg()) - { - addAttribute("default_arg", "1"); - PrintStmt(argDecl->getDefaultArg()); - } - toParent(); - } - - if (FT->isVariadic()) { - addSubNode("Ellipsis").toParent(); - } - } else { - assert(isa<FunctionNoProtoType>(AFT)); - } -} - -//--------------------------------------------------------- -void DocumentXML::addRefAttribute(const NamedDecl* D) -{ - // FIXME: in case of CXX inline member functions referring to a member defined - // after the function it needs to be tested, if the ids are already there - // (should work, but I couldn't test it) - if (const DeclContext* DC = dyn_cast<DeclContext>(D)) - { - addAttribute("ref", getPrefixedId(Contexts[DC], ID_NORMAL)); - } - else - { - addAttribute("ref", getPrefixedId(Decls[D], ID_NORMAL)); - } -} - -//--------------------------------------------------------- -void DocumentXML::addDeclIdAttribute(const NamedDecl* D) -{ - addToMap(Decls, D); - addAttribute("id", getPrefixedId(Decls[D], ID_NORMAL)); -} - -//--------------------------------------------------------- void DocumentXML::PrintDecl(Decl *D) { - addSubNode(D->getDeclKindName()); - addContextAttribute(D->getDeclContext()); - addLocation(D->getLocation()); - if (DeclContext* DC = dyn_cast<DeclContext>(D)) - { - addContextAttribute(DC, CONTEXT_AS_ID); - } - - if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) { - addAttribute("name", ND->getNameAsString()); - - if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { - PrintFunctionDecl(FD); - if (Stmt *Body = FD->getBody(*Ctx)) { - addSubNode("Body"); - PrintStmt(Body); - toParent(); - } - } else if (RecordDecl *RD = dyn_cast<RecordDecl>(D)) { - addBasicTypeRecursively(RD->getTypeForDecl()); - addAttribute("type", getPrefixedId(BasicTypes[RD->getTypeForDecl()], ID_NORMAL)); - if (!RD->isDefinition()) - { - addAttribute("forward", "1"); - } - - for (RecordDecl::field_iterator i = RD->field_begin(*Ctx), e = RD->field_end(*Ctx); i != e; ++i) - { - PrintDecl(*i); - } - } else if (EnumDecl *ED = dyn_cast<EnumDecl>(D)) { - const QualType& enumType = ED->getIntegerType(); - if (!enumType.isNull()) - { - addTypeAttribute(enumType); - for (EnumDecl::enumerator_iterator i = ED->enumerator_begin(*Ctx), e = ED->enumerator_end(*Ctx); i != e; ++i) - { - PrintDecl(*i); - } - } - } else if (EnumConstantDecl* ECD = dyn_cast<EnumConstantDecl>(D)) { - addTypeAttribute(ECD->getType()); - addAttribute("value", ECD->getInitVal().toString(10, true)); - if (ECD->getInitExpr()) - { - PrintStmt(ECD->getInitExpr()); - } - } else if (FieldDecl *FdD = dyn_cast<FieldDecl>(D)) { - addTypeAttribute(FdD->getType()); - addDeclIdAttribute(ND); - if (FdD->isMutable()) - addAttribute("mutable", "1"); - if (FdD->isBitField()) - { - addAttribute("bitfield", "1"); - PrintStmt(FdD->getBitWidth()); - } - } else if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) { - addTypeIdAttribute(Ctx->getTypedefType(TD).getTypePtr()); - addTypeAttribute(TD->getUnderlyingType()); - } else if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) { - addTypeAttribute(VD->getType()); - addDeclIdAttribute(ND); - - VarDecl *V = dyn_cast<VarDecl>(VD); - if (V && V->getStorageClass() != VarDecl::None) - { - addAttribute("storage_class", VarDecl::getStorageClassSpecifierString(V->getStorageClass())); - } - - if (V && V->getInit()) - { - PrintStmt(V->getInit()); - } - } - } else if (LinkageSpecDecl* LSD = dyn_cast<LinkageSpecDecl>(D)) { - switch (LSD->getLanguage()) - { - case LinkageSpecDecl::lang_c: addAttribute("lang", "C"); break; - case LinkageSpecDecl::lang_cxx: addAttribute("lang", "CXX"); break; - default: assert(0 && "Unexpected lang id"); - } - } else if (isa<FileScopeAsmDecl>(D)) { - // FIXME: Implement this - } else { - assert(0 && "Unexpected decl"); - } - toParent(); + writeDeclToXML(D); } //--------------------------------------------------------- diff --git a/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp index 6383c20..7a2b3a7 100644 --- a/lib/Frontend/InitHeaderSearch.cpp +++ b/lib/Frontend/InitHeaderSearch.cpp @@ -138,6 +138,12 @@ void InitHeaderSearch::AddDefaultSystemIncludePaths(const LangOptions &Lang) { false); AddPath("/usr/include/c++/4.1.3/backward", System, true, false, false); + // Ubuntu 9.04 + AddPath("/usr/include/c++/4.3.3", System, true, false, false); + AddPath("/usr/include/c++/4.3.3/x86_64-linux-gnu/", System, true, false, + false); + AddPath("/usr/include/c++/4.3.3/backward", System, true, false, false); + // Fedora 8 AddPath("/usr/include/c++/4.1.2", System, true, false, false); AddPath("/usr/include/c++/4.1.2/i386-redhat-linux", System, true, false, diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp index 6cff75d..41908ad 100644 --- a/lib/Frontend/InitPreprocessor.cpp +++ b/lib/Frontend/InitPreprocessor.cpp @@ -472,11 +472,7 @@ bool InitializePreprocessor(Preprocessor &PP, AddImplicitIncludePTH(PredefineBuffer, PP, I->first); else AddImplicitInclude(PredefineBuffer, I->first); - } - - LineDirective = "# 2 \"<built-in>\" 2 3\n"; - PredefineBuffer.insert(PredefineBuffer.end(), - LineDirective, LineDirective+strlen(LineDirective)); + } // Null terminate PredefinedBuffer and add it. PredefineBuffer.push_back(0); diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp index 87fc839..96f21f1 100644 --- a/lib/Frontend/PCHReader.cpp +++ b/lib/Frontend/PCHReader.cpp @@ -36,11 +36,321 @@ using namespace clang; //===----------------------------------------------------------------------===// +// PCH reader validator implementation +//===----------------------------------------------------------------------===// + +PCHReaderListener::~PCHReaderListener() {} + +bool +PCHValidator::ReadLanguageOptions(const LangOptions &LangOpts) { + const LangOptions &PPLangOpts = PP.getLangOptions(); +#define PARSE_LANGOPT_BENIGN(Option) +#define PARSE_LANGOPT_IMPORTANT(Option, DiagID) \ + if (PPLangOpts.Option != LangOpts.Option) { \ + Reader.Diag(DiagID) << LangOpts.Option << PPLangOpts.Option; \ + return true; \ + } + + PARSE_LANGOPT_BENIGN(Trigraphs); + PARSE_LANGOPT_BENIGN(BCPLComment); + PARSE_LANGOPT_BENIGN(DollarIdents); + PARSE_LANGOPT_BENIGN(AsmPreprocessor); + PARSE_LANGOPT_IMPORTANT(GNUMode, diag::warn_pch_gnu_extensions); + PARSE_LANGOPT_BENIGN(ImplicitInt); + PARSE_LANGOPT_BENIGN(Digraphs); + PARSE_LANGOPT_BENIGN(HexFloats); + PARSE_LANGOPT_IMPORTANT(C99, diag::warn_pch_c99); + PARSE_LANGOPT_IMPORTANT(Microsoft, diag::warn_pch_microsoft_extensions); + PARSE_LANGOPT_IMPORTANT(CPlusPlus, diag::warn_pch_cplusplus); + PARSE_LANGOPT_IMPORTANT(CPlusPlus0x, diag::warn_pch_cplusplus0x); + PARSE_LANGOPT_BENIGN(CXXOperatorName); + PARSE_LANGOPT_IMPORTANT(ObjC1, diag::warn_pch_objective_c); + PARSE_LANGOPT_IMPORTANT(ObjC2, diag::warn_pch_objective_c2); + PARSE_LANGOPT_IMPORTANT(ObjCNonFragileABI, diag::warn_pch_nonfragile_abi); + PARSE_LANGOPT_BENIGN(PascalStrings); + PARSE_LANGOPT_BENIGN(WritableStrings); + PARSE_LANGOPT_IMPORTANT(LaxVectorConversions, + diag::warn_pch_lax_vector_conversions); + PARSE_LANGOPT_IMPORTANT(Exceptions, diag::warn_pch_exceptions); + PARSE_LANGOPT_IMPORTANT(NeXTRuntime, diag::warn_pch_objc_runtime); + PARSE_LANGOPT_IMPORTANT(Freestanding, diag::warn_pch_freestanding); + PARSE_LANGOPT_IMPORTANT(NoBuiltin, diag::warn_pch_builtins); + PARSE_LANGOPT_IMPORTANT(ThreadsafeStatics, + diag::warn_pch_thread_safe_statics); + PARSE_LANGOPT_IMPORTANT(Blocks, diag::warn_pch_blocks); + PARSE_LANGOPT_BENIGN(EmitAllDecls); + PARSE_LANGOPT_IMPORTANT(MathErrno, diag::warn_pch_math_errno); + PARSE_LANGOPT_IMPORTANT(OverflowChecking, diag::warn_pch_overflow_checking); + PARSE_LANGOPT_IMPORTANT(HeinousExtensions, + diag::warn_pch_heinous_extensions); + // FIXME: Most of the options below are benign if the macro wasn't + // used. Unfortunately, this means that a PCH compiled without + // optimization can't be used with optimization turned on, even + // though the only thing that changes is whether __OPTIMIZE__ was + // defined... but if __OPTIMIZE__ never showed up in the header, it + // doesn't matter. We could consider making this some special kind + // of check. + PARSE_LANGOPT_IMPORTANT(Optimize, diag::warn_pch_optimize); + PARSE_LANGOPT_IMPORTANT(OptimizeSize, diag::warn_pch_optimize_size); + PARSE_LANGOPT_IMPORTANT(Static, diag::warn_pch_static); + PARSE_LANGOPT_IMPORTANT(PICLevel, diag::warn_pch_pic_level); + PARSE_LANGOPT_IMPORTANT(GNUInline, diag::warn_pch_gnu_inline); + PARSE_LANGOPT_IMPORTANT(NoInline, diag::warn_pch_no_inline); + PARSE_LANGOPT_IMPORTANT(AccessControl, diag::warn_pch_access_control); + PARSE_LANGOPT_IMPORTANT(CharIsSigned, diag::warn_pch_char_signed); + if ((PPLangOpts.getGCMode() != 0) != (LangOpts.getGCMode() != 0)) { + Reader.Diag(diag::warn_pch_gc_mode) + << LangOpts.getGCMode() << PPLangOpts.getGCMode(); + return true; + } + PARSE_LANGOPT_BENIGN(getVisibilityMode()); + PARSE_LANGOPT_BENIGN(InstantiationDepth); +#undef PARSE_LANGOPT_IRRELEVANT +#undef PARSE_LANGOPT_BENIGN + + return false; +} + +bool PCHValidator::ReadTargetTriple(const std::string &Triple) { + if (Triple != PP.getTargetInfo().getTargetTriple()) { + Reader.Diag(diag::warn_pch_target_triple) + << Triple << PP.getTargetInfo().getTargetTriple(); + return true; + } + return false; +} + +/// \brief Split the given string into a vector of lines, eliminating +/// any empty lines in the process. +/// +/// \param Str the string to split. +/// \param Len the length of Str. +/// \param KeepEmptyLines true if empty lines should be included +/// \returns a vector of lines, with the line endings removed +static std::vector<std::string> splitLines(const char *Str, unsigned Len, + bool KeepEmptyLines = false) { + std::vector<std::string> Lines; + for (unsigned LineStart = 0; LineStart < Len; ++LineStart) { + unsigned LineEnd = LineStart; + while (LineEnd < Len && Str[LineEnd] != '\n') + ++LineEnd; + if (LineStart != LineEnd || KeepEmptyLines) + Lines.push_back(std::string(&Str[LineStart], &Str[LineEnd])); + LineStart = LineEnd; + } + return Lines; +} + +/// \brief Determine whether the string Haystack starts with the +/// substring Needle. +static bool startsWith(const std::string &Haystack, const char *Needle) { + for (unsigned I = 0, N = Haystack.size(); Needle[I] != 0; ++I) { + if (I == N) + return false; + if (Haystack[I] != Needle[I]) + return false; + } + + return true; +} + +/// \brief Determine whether the string Haystack starts with the +/// substring Needle. +static inline bool startsWith(const std::string &Haystack, + const std::string &Needle) { + return startsWith(Haystack, Needle.c_str()); +} + +bool PCHValidator::ReadPredefinesBuffer(const char *PCHPredef, + unsigned PCHPredefLen, + FileID PCHBufferID, + std::string &SuggestedPredefines) { + const char *Predef = PP.getPredefines().c_str(); + unsigned PredefLen = PP.getPredefines().size(); + + // If the two predefines buffers compare equal, we're done! + if (PredefLen == PCHPredefLen && + strncmp(Predef, PCHPredef, PCHPredefLen) == 0) + return false; + + SourceManager &SourceMgr = PP.getSourceManager(); + + // The predefines buffers are different. Determine what the + // differences are, and whether they require us to reject the PCH + // file. + std::vector<std::string> CmdLineLines = splitLines(Predef, PredefLen); + std::vector<std::string> PCHLines = splitLines(PCHPredef, PCHPredefLen); + + // Sort both sets of predefined buffer lines, since + std::sort(CmdLineLines.begin(), CmdLineLines.end()); + std::sort(PCHLines.begin(), PCHLines.end()); + + // Determine which predefines that where used to build the PCH file + // are missing from the command line. + std::vector<std::string> MissingPredefines; + std::set_difference(PCHLines.begin(), PCHLines.end(), + CmdLineLines.begin(), CmdLineLines.end(), + std::back_inserter(MissingPredefines)); + + bool MissingDefines = false; + bool ConflictingDefines = false; + for (unsigned I = 0, N = MissingPredefines.size(); I != N; ++I) { + const std::string &Missing = MissingPredefines[I]; + if (!startsWith(Missing, "#define ") != 0) { + Reader.Diag(diag::warn_pch_compiler_options_mismatch); + return true; + } + + // This is a macro definition. Determine the name of the macro + // we're defining. + std::string::size_type StartOfMacroName = strlen("#define "); + std::string::size_type EndOfMacroName + = Missing.find_first_of("( \n\r", StartOfMacroName); + assert(EndOfMacroName != std::string::npos && + "Couldn't find the end of the macro name"); + std::string MacroName = Missing.substr(StartOfMacroName, + EndOfMacroName - StartOfMacroName); + + // Determine whether this macro was given a different definition + // on the command line. + std::string MacroDefStart = "#define " + MacroName; + std::string::size_type MacroDefLen = MacroDefStart.size(); + std::vector<std::string>::iterator ConflictPos + = std::lower_bound(CmdLineLines.begin(), CmdLineLines.end(), + MacroDefStart); + for (; ConflictPos != CmdLineLines.end(); ++ConflictPos) { + if (!startsWith(*ConflictPos, MacroDefStart)) { + // Different macro; we're done. + ConflictPos = CmdLineLines.end(); + break; + } + + assert(ConflictPos->size() > MacroDefLen && + "Invalid #define in predefines buffer?"); + if ((*ConflictPos)[MacroDefLen] != ' ' && + (*ConflictPos)[MacroDefLen] != '(') + continue; // Longer macro name; keep trying. + + // We found a conflicting macro definition. + break; + } + + if (ConflictPos != CmdLineLines.end()) { + Reader.Diag(diag::warn_cmdline_conflicting_macro_def) + << MacroName; + + // Show the definition of this macro within the PCH file. + const char *MissingDef = strstr(PCHPredef, Missing.c_str()); + unsigned Offset = MissingDef - PCHPredef; + SourceLocation PCHMissingLoc + = SourceMgr.getLocForStartOfFile(PCHBufferID) + .getFileLocWithOffset(Offset); + Reader.Diag(PCHMissingLoc, diag::note_pch_macro_defined_as) + << MacroName; + + ConflictingDefines = true; + continue; + } + + // If the macro doesn't conflict, then we'll just pick up the + // macro definition from the PCH file. Warn the user that they + // made a mistake. + if (ConflictingDefines) + continue; // Don't complain if there are already conflicting defs + + if (!MissingDefines) { + Reader.Diag(diag::warn_cmdline_missing_macro_defs); + MissingDefines = true; + } + + // Show the definition of this macro within the PCH file. + const char *MissingDef = strstr(PCHPredef, Missing.c_str()); + unsigned Offset = MissingDef - PCHPredef; + SourceLocation PCHMissingLoc + = SourceMgr.getLocForStartOfFile(PCHBufferID) + .getFileLocWithOffset(Offset); + Reader.Diag(PCHMissingLoc, diag::note_using_macro_def_from_pch); + } + + if (ConflictingDefines) + return true; + + // Determine what predefines were introduced based on command-line + // parameters that were not present when building the PCH + // file. Extra #defines are okay, so long as the identifiers being + // defined were not used within the precompiled header. + std::vector<std::string> ExtraPredefines; + std::set_difference(CmdLineLines.begin(), CmdLineLines.end(), + PCHLines.begin(), PCHLines.end(), + std::back_inserter(ExtraPredefines)); + for (unsigned I = 0, N = ExtraPredefines.size(); I != N; ++I) { + const std::string &Extra = ExtraPredefines[I]; + if (!startsWith(Extra, "#define ") != 0) { + Reader.Diag(diag::warn_pch_compiler_options_mismatch); + return true; + } + + // This is an extra macro definition. Determine the name of the + // macro we're defining. + std::string::size_type StartOfMacroName = strlen("#define "); + std::string::size_type EndOfMacroName + = Extra.find_first_of("( \n\r", StartOfMacroName); + assert(EndOfMacroName != std::string::npos && + "Couldn't find the end of the macro name"); + std::string MacroName = Extra.substr(StartOfMacroName, + EndOfMacroName - StartOfMacroName); + + // Check whether this name was used somewhere in the PCH file. If + // so, defining it as a macro could change behavior, so we reject + // the PCH file. + if (IdentifierInfo *II = Reader.get(MacroName.c_str(), + MacroName.c_str() + MacroName.size())) { + Reader.Diag(diag::warn_macro_name_used_in_pch) + << II; + return true; + } + + // Add this definition to the suggested predefines buffer. + SuggestedPredefines += Extra; + SuggestedPredefines += '\n'; + } + + // If we get here, it's because the predefines buffer had compatible + // contents. Accept the PCH file. + return false; +} + +void PCHValidator::ReadHeaderFileInfo(const HeaderFileInfo &HFI) { + PP.getHeaderSearchInfo().setHeaderFileInfoForUID(HFI, NumHeaderInfos++); +} + +void PCHValidator::ReadCounter(unsigned Value) { + PP.setCounterValue(Value); +} + + + +//===----------------------------------------------------------------------===// // PCH reader implementation //===----------------------------------------------------------------------===// PCHReader::PCHReader(Preprocessor &PP, ASTContext *Context) - : SemaObj(0), PP(PP), Context(Context), Consumer(0), + : Listener(new PCHValidator(PP, *this)), SourceMgr(PP.getSourceManager()), + FileMgr(PP.getFileManager()), Diags(PP.getDiagnostics()), + SemaObj(0), PP(&PP), Context(Context), Consumer(0), + IdentifierTableData(0), IdentifierLookupTable(0), + IdentifierOffsets(0), + MethodPoolLookupTable(0), MethodPoolLookupTableData(0), + TotalSelectorsInMethodPool(0), SelectorOffsets(0), + TotalNumSelectors(0), NumStatHits(0), NumStatMisses(0), + NumSLocEntriesRead(0), NumStatementsRead(0), + NumMacrosRead(0), NumMethodPoolSelectorsRead(0), NumMethodPoolMisses(0), + NumLexicalDeclContextsRead(0), NumVisibleDeclContextsRead(0) { } + +PCHReader::PCHReader(SourceManager &SourceMgr, FileManager &FileMgr, + Diagnostic &Diags) + : SourceMgr(SourceMgr), FileMgr(FileMgr), Diags(Diags), + SemaObj(0), PP(0), Context(0), Consumer(0), IdentifierTableData(0), IdentifierLookupTable(0), IdentifierOffsets(0), MethodPoolLookupTable(0), MethodPoolLookupTableData(0), @@ -314,53 +624,11 @@ typedef OnDiskChainedHashTable<PCHIdentifierLookupTrait> // FIXME: use the diagnostics machinery bool PCHReader::Error(const char *Msg) { - Diagnostic &Diags = PP.getDiagnostics(); unsigned DiagID = Diags.getCustomDiagID(Diagnostic::Fatal, Msg); Diag(DiagID); return true; } -/// \brief Split the given string into a vector of lines, eliminating -/// any empty lines in the process. -/// -/// \param Str the string to split. -/// \param Len the length of Str. -/// \param KeepEmptyLines true if empty lines should be included -/// \returns a vector of lines, with the line endings removed -std::vector<std::string> splitLines(const char *Str, unsigned Len, - bool KeepEmptyLines = false) { - std::vector<std::string> Lines; - for (unsigned LineStart = 0; LineStart < Len; ++LineStart) { - unsigned LineEnd = LineStart; - while (LineEnd < Len && Str[LineEnd] != '\n') - ++LineEnd; - if (LineStart != LineEnd || KeepEmptyLines) - Lines.push_back(std::string(&Str[LineStart], &Str[LineEnd])); - LineStart = LineEnd; - } - return Lines; -} - -/// \brief Determine whether the string Haystack starts with the -/// substring Needle. -static bool startsWith(const std::string &Haystack, const char *Needle) { - for (unsigned I = 0, N = Haystack.size(); Needle[I] != 0; ++I) { - if (I == N) - return false; - if (Haystack[I] != Needle[I]) - return false; - } - - return true; -} - -/// \brief Determine whether the string Haystack starts with the -/// substring Needle. -static inline bool startsWith(const std::string &Haystack, - const std::string &Needle) { - return startsWith(Haystack, Needle.c_str()); -} - /// \brief Check the contents of the predefines buffer against the /// contents of the predefines buffer used to build the PCH file. /// @@ -381,158 +649,9 @@ static inline bool startsWith(const std::string &Haystack, bool PCHReader::CheckPredefinesBuffer(const char *PCHPredef, unsigned PCHPredefLen, FileID PCHBufferID) { - const char *Predef = PP.getPredefines().c_str(); - unsigned PredefLen = PP.getPredefines().size(); - - // If the two predefines buffers compare equal, we're done! - if (PredefLen == PCHPredefLen && - strncmp(Predef, PCHPredef, PCHPredefLen) == 0) - return false; - - SourceManager &SourceMgr = PP.getSourceManager(); - - // The predefines buffers are different. Determine what the - // differences are, and whether they require us to reject the PCH - // file. - std::vector<std::string> CmdLineLines = splitLines(Predef, PredefLen); - std::vector<std::string> PCHLines = splitLines(PCHPredef, PCHPredefLen); - - // Sort both sets of predefined buffer lines, since - std::sort(CmdLineLines.begin(), CmdLineLines.end()); - std::sort(PCHLines.begin(), PCHLines.end()); - - // Determine which predefines that where used to build the PCH file - // are missing from the command line. - std::vector<std::string> MissingPredefines; - std::set_difference(PCHLines.begin(), PCHLines.end(), - CmdLineLines.begin(), CmdLineLines.end(), - std::back_inserter(MissingPredefines)); - - bool MissingDefines = false; - bool ConflictingDefines = false; - for (unsigned I = 0, N = MissingPredefines.size(); I != N; ++I) { - const std::string &Missing = MissingPredefines[I]; - if (!startsWith(Missing, "#define ") != 0) { - Diag(diag::warn_pch_compiler_options_mismatch); - return true; - } - - // This is a macro definition. Determine the name of the macro - // we're defining. - std::string::size_type StartOfMacroName = strlen("#define "); - std::string::size_type EndOfMacroName - = Missing.find_first_of("( \n\r", StartOfMacroName); - assert(EndOfMacroName != std::string::npos && - "Couldn't find the end of the macro name"); - std::string MacroName = Missing.substr(StartOfMacroName, - EndOfMacroName - StartOfMacroName); - - // Determine whether this macro was given a different definition - // on the command line. - std::string MacroDefStart = "#define " + MacroName; - std::string::size_type MacroDefLen = MacroDefStart.size(); - std::vector<std::string>::iterator ConflictPos - = std::lower_bound(CmdLineLines.begin(), CmdLineLines.end(), - MacroDefStart); - for (; ConflictPos != CmdLineLines.end(); ++ConflictPos) { - if (!startsWith(*ConflictPos, MacroDefStart)) { - // Different macro; we're done. - ConflictPos = CmdLineLines.end(); - break; - } - - assert(ConflictPos->size() > MacroDefLen && - "Invalid #define in predefines buffer?"); - if ((*ConflictPos)[MacroDefLen] != ' ' && - (*ConflictPos)[MacroDefLen] != '(') - continue; // Longer macro name; keep trying. - - // We found a conflicting macro definition. - break; - } - - if (ConflictPos != CmdLineLines.end()) { - Diag(diag::warn_cmdline_conflicting_macro_def) - << MacroName; - - // Show the definition of this macro within the PCH file. - const char *MissingDef = strstr(PCHPredef, Missing.c_str()); - unsigned Offset = MissingDef - PCHPredef; - SourceLocation PCHMissingLoc - = SourceMgr.getLocForStartOfFile(PCHBufferID) - .getFileLocWithOffset(Offset); - Diag(PCHMissingLoc, diag::note_pch_macro_defined_as) - << MacroName; - - ConflictingDefines = true; - continue; - } - - // If the macro doesn't conflict, then we'll just pick up the - // macro definition from the PCH file. Warn the user that they - // made a mistake. - if (ConflictingDefines) - continue; // Don't complain if there are already conflicting defs - - if (!MissingDefines) { - Diag(diag::warn_cmdline_missing_macro_defs); - MissingDefines = true; - } - - // Show the definition of this macro within the PCH file. - const char *MissingDef = strstr(PCHPredef, Missing.c_str()); - unsigned Offset = MissingDef - PCHPredef; - SourceLocation PCHMissingLoc - = SourceMgr.getLocForStartOfFile(PCHBufferID) - .getFileLocWithOffset(Offset); - Diag(PCHMissingLoc, diag::note_using_macro_def_from_pch); - } - - if (ConflictingDefines) - return true; - - // Determine what predefines were introduced based on command-line - // parameters that were not present when building the PCH - // file. Extra #defines are okay, so long as the identifiers being - // defined were not used within the precompiled header. - std::vector<std::string> ExtraPredefines; - std::set_difference(CmdLineLines.begin(), CmdLineLines.end(), - PCHLines.begin(), PCHLines.end(), - std::back_inserter(ExtraPredefines)); - for (unsigned I = 0, N = ExtraPredefines.size(); I != N; ++I) { - const std::string &Extra = ExtraPredefines[I]; - if (!startsWith(Extra, "#define ") != 0) { - Diag(diag::warn_pch_compiler_options_mismatch); - return true; - } - - // This is an extra macro definition. Determine the name of the - // macro we're defining. - std::string::size_type StartOfMacroName = strlen("#define "); - std::string::size_type EndOfMacroName - = Extra.find_first_of("( \n\r", StartOfMacroName); - assert(EndOfMacroName != std::string::npos && - "Couldn't find the end of the macro name"); - std::string MacroName = Extra.substr(StartOfMacroName, - EndOfMacroName - StartOfMacroName); - - // Check whether this name was used somewhere in the PCH file. If - // so, defining it as a macro could change behavior, so we reject - // the PCH file. - if (IdentifierInfo *II = get(MacroName.c_str(), - MacroName.c_str() + MacroName.size())) { - Diag(diag::warn_macro_name_used_in_pch) - << II; - return true; - } - - // Add this definition to the suggested predefines buffer. - SuggestedPredefines += Extra; - SuggestedPredefines += '\n'; - } - - // If we get here, it's because the predefines buffer had compatible - // contents. Accept the PCH file. + if (Listener) + return Listener->ReadPredefinesBuffer(PCHPredef, PCHPredefLen, PCHBufferID, + SuggestedPredefines); return false; } @@ -714,9 +833,7 @@ PCHReader::PCHReadResult PCHReader::ReadSourceManagerBlock() { return Failure; } - SourceManager &SourceMgr = PP.getSourceManager(); RecordData Record; - unsigned NumHeaderInfos = 0; while (true) { unsigned Code = SLocEntryCursor.ReadCode(); if (Code == llvm::bitc::END_BLOCK) { @@ -761,7 +878,8 @@ PCHReader::PCHReadResult PCHReader::ReadSourceManagerBlock() { HFI.DirInfo = Record[1]; HFI.NumIncludes = Record[2]; HFI.ControllingMacroID = Record[3]; - PP.getHeaderSearchInfo().setHeaderFileInfoForUID(HFI, NumHeaderInfos++); + if (Listener) + Listener->ReadHeaderFileInfo(HFI); break; } @@ -794,7 +912,6 @@ PCHReader::PCHReadResult PCHReader::ReadSLocEntryRecord(unsigned ID) { return Failure; } - SourceManager &SourceMgr = PP.getSourceManager(); RecordData Record; const char *BlobStart; unsigned BlobLen; @@ -804,9 +921,15 @@ PCHReader::PCHReadResult PCHReader::ReadSLocEntryRecord(unsigned ID) { return Failure; case pch::SM_SLOC_FILE_ENTRY: { - const FileEntry *File - = PP.getFileManager().getFile(BlobStart, BlobStart + BlobLen); - // FIXME: Error recovery if file cannot be found. + const FileEntry *File = FileMgr.getFile(BlobStart, BlobStart + BlobLen); + if (File == 0) { + std::string ErrorStr = "could not find file '"; + ErrorStr.append(BlobStart, BlobLen); + ErrorStr += "' referenced by PCH file"; + Error(ErrorStr.c_str()); + return Failure; + } + FileID FID = SourceMgr.createFileID(File, SourceLocation::getFromRawEncoding(Record[1]), (SrcMgr::CharacteristicKind)Record[2], @@ -879,6 +1002,8 @@ bool PCHReader::ReadBlockAbbrevs(llvm::BitstreamCursor &Cursor, } void PCHReader::ReadMacroRecord(uint64_t Offset) { + assert(PP && "Forgot to set Preprocessor ?"); + // Keep track of where we are in the stream, then jump back there // after reading this macro. SavedStreamPosition SavedPosition(Stream); @@ -930,7 +1055,7 @@ void PCHReader::ReadMacroRecord(uint64_t Offset) { SourceLocation Loc = SourceLocation::getFromRawEncoding(Record[1]); bool isUsed = Record[2]; - MacroInfo *MI = PP.AllocateMacroInfo(Loc); + MacroInfo *MI = PP->AllocateMacroInfo(Loc); MI->setIsUsed(isUsed); if (RecType == pch::PP_MACRO_FUNCTION_LIKE) { @@ -947,11 +1072,11 @@ void PCHReader::ReadMacroRecord(uint64_t Offset) { if (isC99VarArgs) MI->setIsC99Varargs(); if (isGNUVarArgs) MI->setIsGNUVarargs(); MI->setArgumentList(MacroArgs.data(), MacroArgs.size(), - PP.getPreprocessorAllocator()); + PP->getPreprocessorAllocator()); } // Finally, install the macro. - PP.setMacroInfo(II, MI); + PP->setMacroInfo(II, MI); // Remember that we saw this macro last so that we add the tokens that // form its body to it. @@ -1092,11 +1217,10 @@ PCHReader::ReadPCHBlock() { return IgnorePCH; } - std::string TargetTriple(BlobStart, BlobLen); - if (TargetTriple != PP.getTargetInfo().getTargetTriple()) { - Diag(diag::warn_pch_target_triple) - << TargetTriple << PP.getTargetInfo().getTargetTriple(); - return IgnorePCH; + if (Listener) { + std::string TargetTriple(BlobStart, BlobLen); + if (Listener->ReadTargetTriple(TargetTriple)) + return IgnorePCH; } break; } @@ -1109,7 +1233,8 @@ PCHReader::ReadPCHBlock() { (const unsigned char *)IdentifierTableData + Record[0], (const unsigned char *)IdentifierTableData, PCHIdentifierLookupTrait(*this)); - PP.getIdentifierTable().setExternalIdentifierLookup(this); + if (PP) + PP->getIdentifierTable().setExternalIdentifierLookup(this); } break; @@ -1120,7 +1245,8 @@ PCHReader::ReadPCHBlock() { } IdentifierOffsets = (const uint32_t *)BlobStart; IdentifiersLoaded.resize(Record[0]); - PP.getHeaderSearchInfo().SetExternalLookup(this); + if (PP) + PP->getHeaderSearchInfo().SetExternalLookup(this); break; case pch::EXTERNAL_DEFINITIONS: @@ -1176,14 +1302,14 @@ PCHReader::ReadPCHBlock() { break; case pch::PP_COUNTER_VALUE: - if (!Record.empty()) - PP.setCounterValue(Record[0]); + if (!Record.empty() && Listener) + Listener->ReadCounter(Record[0]); break; case pch::SOURCE_LOCATION_OFFSETS: SLocOffsets = (const uint32_t *)BlobStart; TotalNumSLocEntries = Record[0]; - PP.getSourceManager().PreallocateSLocEntries(this, + SourceMgr.PreallocateSLocEntries(this, TotalNumSLocEntries, Record[1]); break; @@ -1197,7 +1323,7 @@ PCHReader::ReadPCHBlock() { break; case pch::STAT_CACHE: - PP.getFileManager().setStatCache( + FileMgr.setStatCache( new PCHStatCache((const unsigned char *)BlobStart + Record[0], (const unsigned char *)BlobStart, NumStatHits, NumStatMisses)); @@ -1287,10 +1413,10 @@ PCHReader::PCHReadResult PCHReader::ReadPCH(const std::string &FileName) { // Clear out any preallocated source location entries, so that // the source manager does not try to resolve them later. - PP.getSourceManager().ClearPreallocatedSLocEntries(); + SourceMgr.ClearPreallocatedSLocEntries(); // Remove the stat cache. - PP.getFileManager().setStatCache(0); + FileMgr.setStatCache(0); return IgnorePCH; } @@ -1303,71 +1429,82 @@ PCHReader::PCHReadResult PCHReader::ReadPCH(const std::string &FileName) { break; } } - - // Load the translation unit declaration - if (Context) - ReadDeclRecord(DeclOffsets[0], 0); // Check the predefines buffer. if (CheckPredefinesBuffer(PCHPredefines, PCHPredefinesLen, PCHPredefinesBufferID)) return IgnorePCH; - // Initialization of builtins and library builtins occurs before the - // PCH file is read, so there may be some identifiers that were - // loaded into the IdentifierTable before we intercepted the - // creation of identifiers. Iterate through the list of known - // identifiers and determine whether we have to establish - // preprocessor definitions or top-level identifier declaration - // chains for those identifiers. - // - // We copy the IdentifierInfo pointers to a small vector first, - // since de-serializing declarations or macro definitions can add - // new entries into the identifier table, invalidating the - // iterators. - llvm::SmallVector<IdentifierInfo *, 128> Identifiers; - for (IdentifierTable::iterator Id = PP.getIdentifierTable().begin(), - IdEnd = PP.getIdentifierTable().end(); - Id != IdEnd; ++Id) - Identifiers.push_back(Id->second); - PCHIdentifierLookupTable *IdTable - = (PCHIdentifierLookupTable *)IdentifierLookupTable; - for (unsigned I = 0, N = Identifiers.size(); I != N; ++I) { - IdentifierInfo *II = Identifiers[I]; - // Look in the on-disk hash table for an entry for - PCHIdentifierLookupTrait Info(*this, II); - std::pair<const char*, unsigned> Key(II->getName(), II->getLength()); - PCHIdentifierLookupTable::iterator Pos = IdTable->find(Key, &Info); - if (Pos == IdTable->end()) - continue; - - // Dereferencing the iterator has the effect of populating the - // IdentifierInfo node with the various declarations it needs. - (void)*Pos; + if (PP) { + // Initialization of builtins and library builtins occurs before the + // PCH file is read, so there may be some identifiers that were + // loaded into the IdentifierTable before we intercepted the + // creation of identifiers. Iterate through the list of known + // identifiers and determine whether we have to establish + // preprocessor definitions or top-level identifier declaration + // chains for those identifiers. + // + // We copy the IdentifierInfo pointers to a small vector first, + // since de-serializing declarations or macro definitions can add + // new entries into the identifier table, invalidating the + // iterators. + llvm::SmallVector<IdentifierInfo *, 128> Identifiers; + for (IdentifierTable::iterator Id = PP->getIdentifierTable().begin(), + IdEnd = PP->getIdentifierTable().end(); + Id != IdEnd; ++Id) + Identifiers.push_back(Id->second); + PCHIdentifierLookupTable *IdTable + = (PCHIdentifierLookupTable *)IdentifierLookupTable; + for (unsigned I = 0, N = Identifiers.size(); I != N; ++I) { + IdentifierInfo *II = Identifiers[I]; + // Look in the on-disk hash table for an entry for + PCHIdentifierLookupTrait Info(*this, II); + std::pair<const char*, unsigned> Key(II->getName(), II->getLength()); + PCHIdentifierLookupTable::iterator Pos = IdTable->find(Key, &Info); + if (Pos == IdTable->end()) + continue; + + // Dereferencing the iterator has the effect of populating the + // IdentifierInfo node with the various declarations it needs. + (void)*Pos; + } } - // Load the special types. - if (Context) { - Context->setBuiltinVaListType( - GetType(SpecialTypes[pch::SPECIAL_TYPE_BUILTIN_VA_LIST])); - if (unsigned Id = SpecialTypes[pch::SPECIAL_TYPE_OBJC_ID]) - Context->setObjCIdType(GetType(Id)); - if (unsigned Sel = SpecialTypes[pch::SPECIAL_TYPE_OBJC_SELECTOR]) - Context->setObjCSelType(GetType(Sel)); - if (unsigned Proto = SpecialTypes[pch::SPECIAL_TYPE_OBJC_PROTOCOL]) - Context->setObjCProtoType(GetType(Proto)); - if (unsigned Class = SpecialTypes[pch::SPECIAL_TYPE_OBJC_CLASS]) - Context->setObjCClassType(GetType(Class)); - if (unsigned String = SpecialTypes[pch::SPECIAL_TYPE_CF_CONSTANT_STRING]) - Context->setCFConstantStringType(GetType(String)); - if (unsigned FastEnum - = SpecialTypes[pch::SPECIAL_TYPE_OBJC_FAST_ENUMERATION_STATE]) - Context->setObjCFastEnumerationStateType(GetType(FastEnum)); - } + if (Context) + InitializeContext(*Context); return Success; } +void PCHReader::InitializeContext(ASTContext &Ctx) { + Context = &Ctx; + assert(Context && "Passed null context!"); + + assert(PP && "Forgot to set Preprocessor ?"); + PP->getIdentifierTable().setExternalIdentifierLookup(this); + PP->getHeaderSearchInfo().SetExternalLookup(this); + + // Load the translation unit declaration + ReadDeclRecord(DeclOffsets[0], 0); + + // Load the special types. + Context->setBuiltinVaListType( + GetType(SpecialTypes[pch::SPECIAL_TYPE_BUILTIN_VA_LIST])); + if (unsigned Id = SpecialTypes[pch::SPECIAL_TYPE_OBJC_ID]) + Context->setObjCIdType(GetType(Id)); + if (unsigned Sel = SpecialTypes[pch::SPECIAL_TYPE_OBJC_SELECTOR]) + Context->setObjCSelType(GetType(Sel)); + if (unsigned Proto = SpecialTypes[pch::SPECIAL_TYPE_OBJC_PROTOCOL]) + Context->setObjCProtoType(GetType(Proto)); + if (unsigned Class = SpecialTypes[pch::SPECIAL_TYPE_OBJC_CLASS]) + Context->setObjCClassType(GetType(Class)); + if (unsigned String = SpecialTypes[pch::SPECIAL_TYPE_CF_CONSTANT_STRING]) + Context->setCFConstantStringType(GetType(String)); + if (unsigned FastEnum + = SpecialTypes[pch::SPECIAL_TYPE_OBJC_FAST_ENUMERATION_STATE]) + Context->setObjCFastEnumerationStateType(GetType(FastEnum)); +} + /// \brief Retrieve the name of the original source file name /// directly from the PCH file, without actually loading the PCH /// file. @@ -1465,73 +1602,60 @@ std::string PCHReader::getOriginalSourceFile(const std::string &PCHFileName) { /// \returns true if the PCH file is unacceptable, false otherwise. bool PCHReader::ParseLanguageOptions( const llvm::SmallVectorImpl<uint64_t> &Record) { - const LangOptions &LangOpts = PP.getLangOptions(); -#define PARSE_LANGOPT_BENIGN(Option) ++Idx -#define PARSE_LANGOPT_IMPORTANT(Option, DiagID) \ - if (Record[Idx] != LangOpts.Option) { \ - Diag(DiagID) << (unsigned)Record[Idx] << LangOpts.Option; \ - return true; \ - } \ - ++Idx - - unsigned Idx = 0; - PARSE_LANGOPT_BENIGN(Trigraphs); - PARSE_LANGOPT_BENIGN(BCPLComment); - PARSE_LANGOPT_BENIGN(DollarIdents); - PARSE_LANGOPT_BENIGN(AsmPreprocessor); - PARSE_LANGOPT_IMPORTANT(GNUMode, diag::warn_pch_gnu_extensions); - PARSE_LANGOPT_BENIGN(ImplicitInt); - PARSE_LANGOPT_BENIGN(Digraphs); - PARSE_LANGOPT_BENIGN(HexFloats); - PARSE_LANGOPT_IMPORTANT(C99, diag::warn_pch_c99); - PARSE_LANGOPT_IMPORTANT(Microsoft, diag::warn_pch_microsoft_extensions); - PARSE_LANGOPT_IMPORTANT(CPlusPlus, diag::warn_pch_cplusplus); - PARSE_LANGOPT_IMPORTANT(CPlusPlus0x, diag::warn_pch_cplusplus0x); - PARSE_LANGOPT_BENIGN(CXXOperatorName); - PARSE_LANGOPT_IMPORTANT(ObjC1, diag::warn_pch_objective_c); - PARSE_LANGOPT_IMPORTANT(ObjC2, diag::warn_pch_objective_c2); - PARSE_LANGOPT_IMPORTANT(ObjCNonFragileABI, diag::warn_pch_nonfragile_abi); - PARSE_LANGOPT_BENIGN(PascalStrings); - PARSE_LANGOPT_BENIGN(WritableStrings); - PARSE_LANGOPT_IMPORTANT(LaxVectorConversions, - diag::warn_pch_lax_vector_conversions); - PARSE_LANGOPT_IMPORTANT(Exceptions, diag::warn_pch_exceptions); - PARSE_LANGOPT_IMPORTANT(NeXTRuntime, diag::warn_pch_objc_runtime); - PARSE_LANGOPT_IMPORTANT(Freestanding, diag::warn_pch_freestanding); - PARSE_LANGOPT_IMPORTANT(NoBuiltin, diag::warn_pch_builtins); - PARSE_LANGOPT_IMPORTANT(ThreadsafeStatics, - diag::warn_pch_thread_safe_statics); - PARSE_LANGOPT_IMPORTANT(Blocks, diag::warn_pch_blocks); - PARSE_LANGOPT_BENIGN(EmitAllDecls); - PARSE_LANGOPT_IMPORTANT(MathErrno, diag::warn_pch_math_errno); - PARSE_LANGOPT_IMPORTANT(OverflowChecking, diag::warn_pch_overflow_checking); - PARSE_LANGOPT_IMPORTANT(HeinousExtensions, - diag::warn_pch_heinous_extensions); - // FIXME: Most of the options below are benign if the macro wasn't - // used. Unfortunately, this means that a PCH compiled without - // optimization can't be used with optimization turned on, even - // though the only thing that changes is whether __OPTIMIZE__ was - // defined... but if __OPTIMIZE__ never showed up in the header, it - // doesn't matter. We could consider making this some special kind - // of check. - PARSE_LANGOPT_IMPORTANT(Optimize, diag::warn_pch_optimize); - PARSE_LANGOPT_IMPORTANT(OptimizeSize, diag::warn_pch_optimize_size); - PARSE_LANGOPT_IMPORTANT(Static, diag::warn_pch_static); - PARSE_LANGOPT_IMPORTANT(PICLevel, diag::warn_pch_pic_level); - PARSE_LANGOPT_IMPORTANT(GNUInline, diag::warn_pch_gnu_inline); - PARSE_LANGOPT_IMPORTANT(NoInline, diag::warn_pch_no_inline); - PARSE_LANGOPT_IMPORTANT(AccessControl, diag::warn_pch_access_control); - PARSE_LANGOPT_IMPORTANT(CharIsSigned, diag::warn_pch_char_signed); - if ((LangOpts.getGCMode() != 0) != (Record[Idx] != 0)) { - Diag(diag::warn_pch_gc_mode) - << (unsigned)Record[Idx] << LangOpts.getGCMode(); - return true; + if (Listener) { + LangOptions LangOpts; + + #define PARSE_LANGOPT(Option) \ + LangOpts.Option = Record[Idx]; \ + ++Idx + + unsigned Idx = 0; + PARSE_LANGOPT(Trigraphs); + PARSE_LANGOPT(BCPLComment); + PARSE_LANGOPT(DollarIdents); + PARSE_LANGOPT(AsmPreprocessor); + PARSE_LANGOPT(GNUMode); + PARSE_LANGOPT(ImplicitInt); + PARSE_LANGOPT(Digraphs); + PARSE_LANGOPT(HexFloats); + PARSE_LANGOPT(C99); + PARSE_LANGOPT(Microsoft); + PARSE_LANGOPT(CPlusPlus); + PARSE_LANGOPT(CPlusPlus0x); + PARSE_LANGOPT(CXXOperatorNames); + PARSE_LANGOPT(ObjC1); + PARSE_LANGOPT(ObjC2); + PARSE_LANGOPT(ObjCNonFragileABI); + PARSE_LANGOPT(PascalStrings); + PARSE_LANGOPT(WritableStrings); + PARSE_LANGOPT(LaxVectorConversions); + PARSE_LANGOPT(Exceptions); + PARSE_LANGOPT(NeXTRuntime); + PARSE_LANGOPT(Freestanding); + PARSE_LANGOPT(NoBuiltin); + PARSE_LANGOPT(ThreadsafeStatics); + PARSE_LANGOPT(Blocks); + PARSE_LANGOPT(EmitAllDecls); + PARSE_LANGOPT(MathErrno); + PARSE_LANGOPT(OverflowChecking); + PARSE_LANGOPT(HeinousExtensions); + PARSE_LANGOPT(Optimize); + PARSE_LANGOPT(OptimizeSize); + PARSE_LANGOPT(Static); + PARSE_LANGOPT(PICLevel); + PARSE_LANGOPT(GNUInline); + PARSE_LANGOPT(NoInline); + PARSE_LANGOPT(AccessControl); + PARSE_LANGOPT(CharIsSigned); + LangOpts.setGCMode((LangOptions::GCMode)Record[Idx]); + ++Idx; + LangOpts.setVisibilityMode((LangOptions::VisibilityMode)Record[Idx]); + ++Idx; + PARSE_LANGOPT(InstantiationDepth); + #undef PARSE_LANGOPT + + return Listener->ReadLanguageOptions(LangOpts); } - ++Idx; - PARSE_LANGOPT_BENIGN(getVisibilityMode()); - PARSE_LANGOPT_BENIGN(InstantiationDepth); -#undef PARSE_LANGOPT_IRRELEVANT -#undef PARSE_LANGOPT_BENIGN return false; } @@ -1722,13 +1846,15 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) { return Context->getObjCQualifiedInterfaceType(ItfD, Protos.data(), NumProtos); } - case pch::TYPE_OBJC_QUALIFIED_ID: { + case pch::TYPE_OBJC_OBJECT_POINTER: { unsigned Idx = 0; + ObjCInterfaceDecl *ItfD = + cast_or_null<ObjCInterfaceDecl>(GetDecl(Record[Idx++])); unsigned NumProtos = Record[Idx++]; llvm::SmallVector<ObjCProtocolDecl*, 4> Protos; for (unsigned I = 0; I != NumProtos; ++I) Protos.push_back(cast<ObjCProtocolDecl>(GetDecl(Record[Idx++]))); - return Context->getObjCQualifiedIdType(Protos.data(), NumProtos); + return Context->getObjCObjectPointerType(ItfD, Protos.data(), NumProtos); } } // Suppress a GCC warning @@ -2056,6 +2182,7 @@ IdentifierInfo *PCHReader::DecodeIdentifierInfo(unsigned ID) { return 0; } + assert(PP && "Forgot to set Preprocessor ?"); if (!IdentifiersLoaded[ID - 1]) { uint32_t Offset = IdentifierOffsets[ID - 1]; const char *Str = IdentifierTableData + Offset; @@ -2067,7 +2194,7 @@ IdentifierInfo *PCHReader::DecodeIdentifierInfo(unsigned ID) { unsigned StrLen = (((unsigned) StrLenPtr[0]) | (((unsigned) StrLenPtr[1]) << 8)) - 1; IdentifiersLoaded[ID - 1] - = &PP.getIdentifierTable().get(Str, Str + StrLen); + = &PP->getIdentifierTable().get(Str, Str + StrLen); } return IdentifiersLoaded[ID - 1]; @@ -2170,15 +2297,14 @@ DiagnosticBuilder PCHReader::Diag(unsigned DiagID) { } DiagnosticBuilder PCHReader::Diag(SourceLocation Loc, unsigned DiagID) { - return PP.getDiagnostics().Report(FullSourceLoc(Loc, - PP.getSourceManager()), - DiagID); + return Diags.Report(FullSourceLoc(Loc, SourceMgr), DiagID); } /// \brief Retrieve the identifier table associated with the /// preprocessor. IdentifierTable &PCHReader::getIdentifierTable() { - return PP.getIdentifierTable(); + assert(PP && "Forgot to set Preprocessor ?"); + return PP->getIdentifierTable(); } /// \brief Record that the given ID maps to the given switch-case diff --git a/lib/Frontend/PCHReaderDecl.cpp b/lib/Frontend/PCHReaderDecl.cpp index 6856623..3dd84c7 100644 --- a/lib/Frontend/PCHReaderDecl.cpp +++ b/lib/Frontend/PCHReaderDecl.cpp @@ -80,8 +80,9 @@ void PCHDeclReader::VisitDecl(Decl *D) { D->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++])); D->setInvalidDecl(Record[Idx++]); if (Record[Idx++]) - D->addAttr(Reader.ReadAttributes()); + D->addAttr(*Reader.getContext(), Reader.ReadAttributes()); D->setImplicit(Record[Idx++]); + D->setUsed(Record[Idx++]); D->setAccess((AccessSpecifier)Record[Idx++]); } @@ -156,6 +157,7 @@ void PCHDeclReader::VisitFunctionDecl(FunctionDecl *FD) { FD->setHasWrittenPrototype(Record[Idx++]); FD->setDeleted(Record[Idx++]); FD->setTypeSpecStartLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + FD->setLocEnd(SourceLocation::getFromRawEncoding(Record[Idx++])); // FIXME: C++ TemplateOrInstantiation unsigned NumParams = Record[Idx++]; llvm::SmallVector<ParmVarDecl *, 16> Params; diff --git a/lib/Frontend/PCHReaderStmt.cpp b/lib/Frontend/PCHReaderStmt.cpp index e6871e3..d096388 100644 --- a/lib/Frontend/PCHReaderStmt.cpp +++ b/lib/Frontend/PCHReaderStmt.cpp @@ -667,6 +667,7 @@ unsigned PCHStmtReader::VisitBlockDeclRefExpr(BlockDeclRefExpr *E) { E->setDecl(cast<ValueDecl>(Reader.GetDecl(Record[Idx++]))); E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++])); E->setByRef(Record[Idx++]); + E->setConstQualAdded(Record[Idx++]); return 0; } diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp index 765fecb..3b1eb08 100644 --- a/lib/Frontend/PCHWriter.cpp +++ b/lib/Frontend/PCHWriter.cpp @@ -229,12 +229,14 @@ PCHTypeWriter::VisitObjCQualifiedInterfaceType( Code = pch::TYPE_OBJC_QUALIFIED_INTERFACE; } -void PCHTypeWriter::VisitObjCQualifiedIdType(const ObjCQualifiedIdType *T) { +void +PCHTypeWriter::VisitObjCObjectPointerType(const ObjCObjectPointerType *T) { + Writer.AddDeclRef(T->getDecl(), Record); Record.push_back(T->getNumProtocols()); - for (ObjCQualifiedIdType::qual_iterator I = T->qual_begin(), + for (ObjCInterfaceType::qual_iterator I = T->qual_begin(), E = T->qual_end(); I != E; ++I) Writer.AddDeclRef(*I, Record); - Code = pch::TYPE_OBJC_QUALIFIED_ID; + Code = pch::TYPE_OBJC_OBJECT_POINTER; } //===----------------------------------------------------------------------===// @@ -407,7 +409,7 @@ void PCHWriter::WriteBlockInfoBlock() { RECORD(TYPE_ENUM); RECORD(TYPE_OBJC_INTERFACE); RECORD(TYPE_OBJC_QUALIFIED_INTERFACE); - RECORD(TYPE_OBJC_QUALIFIED_ID); + RECORD(TYPE_OBJC_OBJECT_POINTER); // Statements and Exprs can occur in the Types block. AddStmtsExprs(Stream, Record); diff --git a/lib/Frontend/PCHWriterDecl.cpp b/lib/Frontend/PCHWriterDecl.cpp index 6734661..44da4d7 100644 --- a/lib/Frontend/PCHWriterDecl.cpp +++ b/lib/Frontend/PCHWriterDecl.cpp @@ -82,6 +82,7 @@ void PCHDeclWriter::VisitDecl(Decl *D) { Record.push_back(D->isInvalidDecl()); Record.push_back(D->hasAttrs()); Record.push_back(D->isImplicit()); + Record.push_back(D->isUsed()); Record.push_back(D->getAccess()); } @@ -156,6 +157,7 @@ void PCHDeclWriter::VisitFunctionDecl(FunctionDecl *D) { Record.push_back(D->hasWrittenPrototype()); Record.push_back(D->isDeleted()); Writer.AddSourceLocation(D->getTypeSpecStartLoc(), Record); + Writer.AddSourceLocation(D->getLocEnd(), Record); // FIXME: C++ TemplateOrInstantiation Record.push_back(D->param_size()); for (FunctionDecl::param_iterator P = D->param_begin(), PEnd = D->param_end(); @@ -360,6 +362,7 @@ void PCHDeclWriter::VisitParmVarDecl(ParmVarDecl *D) { // know are true of all PARM_VAR_DECLs. if (!D->hasAttrs() && !D->isImplicit() && + !D->isUsed() && D->getAccess() == AS_none && D->getStorageClass() == 0 && !D->hasCXXDirectInitializer() && // Can params have this ever? @@ -434,6 +437,7 @@ void PCHWriter::WriteDeclsBlockAbbrevs() { Abv->Add(BitCodeAbbrevOp(0)); // isInvalidDecl (!?) Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs Abv->Add(BitCodeAbbrevOp(0)); // isImplicit + Abv->Add(BitCodeAbbrevOp(0)); // isUsed Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier // NamedDecl @@ -516,7 +520,7 @@ void PCHWriter::WriteDeclsBlock(ASTContext &Context) { // If the declaration had any attributes, write them now. if (D->hasAttrs()) - WriteAttributeRecord(D->getAttrs()); + WriteAttributeRecord(D->getAttrs(Context)); // Flush any expressions that were written as part of this declaration. FlushStmts(); diff --git a/lib/Frontend/PCHWriterStmt.cpp b/lib/Frontend/PCHWriterStmt.cpp index 73dea10..c63c03c 100644 --- a/lib/Frontend/PCHWriterStmt.cpp +++ b/lib/Frontend/PCHWriterStmt.cpp @@ -602,6 +602,7 @@ void PCHStmtWriter::VisitBlockDeclRefExpr(BlockDeclRefExpr *E) { Writer.AddDeclRef(E->getDecl(), Record); Writer.AddSourceLocation(E->getLocation(), Record); Record.push_back(E->isByRef()); + Record.push_back(E->isConstQualAdded()); Code = pch::EXPR_BLOCK_DECL_REF; } diff --git a/lib/Frontend/PrintPreprocessedOutput.cpp b/lib/Frontend/PrintPreprocessedOutput.cpp index 89d099c..d63d9cb 100644 --- a/lib/Frontend/PrintPreprocessedOutput.cpp +++ b/lib/Frontend/PrintPreprocessedOutput.cpp @@ -123,6 +123,8 @@ public: } void WriteLineInfo(unsigned LineNo, const char *Extra=0, unsigned ExtraLen=0); + void HandleNewlinesInToken(const char *TokStr, unsigned Len); + /// MacroDefined - This hook is called whenever a macro definition is seen. void MacroDefined(const IdentifierInfo *II, const MacroInfo *MI); @@ -327,6 +329,29 @@ bool PrintPPOutputPPCallbacks::HandleFirstTokOnLine(Token &Tok) { return true; } +void PrintPPOutputPPCallbacks::HandleNewlinesInToken(const char *TokStr, + unsigned Len) { + unsigned NumNewlines = 0; + for (; Len; --Len, ++TokStr) { + if (*TokStr != '\n' && + *TokStr != '\r') + continue; + + ++NumNewlines; + + // If we have \n\r or \r\n, skip both and count as one line. + if (Len != 1 && + (TokStr[1] == '\n' || TokStr[1] == '\r') && + TokStr[0] != TokStr[1]) + ++TokStr, --Len; + } + + if (NumNewlines == 0) return; + + CurLine += NumNewlines; +} + + namespace { struct UnknownPragmaHandler : public PragmaHandler { const char *Prefix; @@ -382,9 +407,19 @@ static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok, const char *TokPtr = Buffer; unsigned Len = PP.getSpelling(Tok, TokPtr); OS.write(TokPtr, Len); + + // Tokens that can contain embedded newlines need to adjust our current + // line number. + if (Tok.getKind() == tok::comment) + Callbacks->HandleNewlinesInToken(TokPtr, Len); } else { std::string S = PP.getSpelling(Tok); OS.write(&S[0], S.size()); + + // Tokens that can contain embedded newlines need to adjust our current + // line number. + if (Tok.getKind() == tok::comment) + Callbacks->HandleNewlinesInToken(&S[0], S.size()); } Callbacks->SetEmittedTokensOnThisLine(); diff --git a/lib/Frontend/RewriteBlocks.cpp b/lib/Frontend/RewriteBlocks.cpp index 8393574..d20d5cd 100644 --- a/lib/Frontend/RewriteBlocks.cpp +++ b/lib/Frontend/RewriteBlocks.cpp @@ -132,7 +132,7 @@ public: if (const PointerType *PT = OCT->getAsPointerType()) { if (isa<ObjCInterfaceType>(PT->getPointeeType()) || - isa<ObjCQualifiedIdType>(PT->getPointeeType())) + PT->getPointeeType()->isObjCQualifiedIdType()) return true; } return false; diff --git a/lib/Frontend/RewriteObjC.cpp b/lib/Frontend/RewriteObjC.cpp index f382704..dce2710 100644 --- a/lib/Frontend/RewriteObjC.cpp +++ b/lib/Frontend/RewriteObjC.cpp @@ -356,7 +356,7 @@ namespace { if (const PointerType *PT = OCT->getAsPointerType()) { if (isa<ObjCInterfaceType>(PT->getPointeeType()) || - isa<ObjCQualifiedIdType>(PT->getPointeeType())) + PT->getPointeeType()->isObjCQualifiedIdType()) return true; } return false; diff --git a/lib/Frontend/StmtXML.cpp b/lib/Frontend/StmtXML.cpp index c861881..6ba0a28 100644 --- a/lib/Frontend/StmtXML.cpp +++ b/lib/Frontend/StmtXML.cpp @@ -28,8 +28,31 @@ namespace { class VISIBILITY_HIDDEN StmtXML : public StmtVisitor<StmtXML> { DocumentXML& Doc; - static const char *getOpcodeStr(UnaryOperator::Opcode Op); - static const char *getOpcodeStr(BinaryOperator::Opcode Op); + //static const char *getOpcodeStr(UnaryOperator::Opcode Op); + //static const char *getOpcodeStr(BinaryOperator::Opcode Op); + + + void addSpecialAttribute(const char* pName, StringLiteral* Str) + { + Doc.addAttribute(pName, Doc.escapeString(Str->getStrData(), Str->getByteLength())); + } + + void addSpecialAttribute(const char* pName, SizeOfAlignOfExpr* S) + { + if (S->isArgumentType()) + { + Doc.addAttribute(pName, S->getArgumentType()); + } + } + + void addSpecialAttribute(const char* pName, CXXTypeidExpr* S) + { + if (S->isTypeOperand()) + { + Doc.addAttribute(pName, S->getTypeOperand()); + } + } + public: StmtXML(DocumentXML& doc) @@ -39,12 +62,21 @@ namespace { void DumpSubTree(Stmt *S) { if (S) { - Doc.addSubNode(S->getStmtClassName()); - Doc.addLocationRange(S->getSourceRange()); - if (DeclStmt* DS = dyn_cast<DeclStmt>(S)) { - VisitDeclStmt(DS); - } else { - Visit(S); + Visit(S); + if (DeclStmt* DS = dyn_cast<DeclStmt>(S)) + { + for (DeclStmt::decl_iterator DI = DS->decl_begin(), DE = DS->decl_end(); + DI != DE; ++DI) + { + Doc.PrintDecl(*DI); + } + } + else + { + if (CXXConditionDeclExpr* CCDE = dyn_cast<CXXConditionDeclExpr>(S)) + { + Doc.PrintDecl(CCDE->getVarDecl()); + } for (Stmt::child_iterator i = S->child_begin(), e = S->child_end(); i != e; ++i) { DumpSubTree(*i); @@ -56,17 +88,46 @@ namespace { } } - void DumpTypeExpr(const QualType& T) - { - Doc.addSubNode("TypeExpr"); - Doc.addTypeAttribute(T); - Doc.toParent(); - } - void DumpExpr(const Expr *Node) { - Doc.addTypeAttribute(Node->getType()); - } +#define NODE_XML( CLASS, NAME ) \ + void Visit##CLASS(CLASS* S) \ + { \ + typedef CLASS tStmtType; \ + Doc.addSubNode(NAME); + +#define ATTRIBUTE_XML( FN, NAME ) Doc.addAttribute(NAME, S->FN); +#define TYPE_ATTRIBUTE_XML( FN ) ATTRIBUTE_XML(FN, "type") +#define ATTRIBUTE_OPT_XML( FN, NAME ) Doc.addAttributeOptional(NAME, S->FN); +#define ATTRIBUTE_SPECIAL_XML( FN, NAME ) addSpecialAttribute(NAME, S); +#define ATTRIBUTE_FILE_LOCATION_XML Doc.addLocationRange(S->getSourceRange()); + +#define ATTRIBUTE_ENUM_XML( FN, NAME ) \ + { \ + const char* pAttributeName = NAME; \ + const bool optional = false; \ + switch (S->FN) { \ + default: assert(0 && "unknown enum value"); + +#define ATTRIBUTE_ENUM_OPT_XML( FN, NAME ) \ + { \ + const char* pAttributeName = NAME; \ + const bool optional = true; \ + switch (S->FN) { \ + default: assert(0 && "unknown enum value"); + +#define ENUM_XML( VALUE, NAME ) case VALUE: if ((!optional) || NAME[0]) Doc.addAttribute(pAttributeName, NAME); break; +#define END_ENUM_XML } } +#define END_NODE_XML } + +#define ID_ATTRIBUTE_XML Doc.addAttribute("id", S); +#define SUB_NODE_XML( CLASS ) +#define SUB_NODE_SEQUENCE_XML( CLASS ) +#define SUB_NODE_OPT_XML( CLASS ) + +#include "clang/Frontend/StmtXML.def" + +#if (0) // Stmts. void VisitStmt(Stmt *Node); void VisitDeclStmt(DeclStmt *Node); @@ -105,13 +166,14 @@ namespace { void VisitObjCKVCRefExpr(ObjCKVCRefExpr *Node); void VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node); void VisitObjCSuperExpr(ObjCSuperExpr *Node); +#endif }; } //===----------------------------------------------------------------------===// // Stmt printing methods. //===----------------------------------------------------------------------===// - +#if (0) void StmtXML::VisitStmt(Stmt *Node) { // nothing special to do @@ -396,7 +458,7 @@ void StmtXML::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) { if (Node->isFreeIvar()) Doc.addAttribute("isFreeIvar", "1"); } - +#endif //===----------------------------------------------------------------------===// // Stmt method implementations //===----------------------------------------------------------------------===// diff --git a/lib/Frontend/TextDiagnosticPrinter.cpp b/lib/Frontend/TextDiagnosticPrinter.cpp index 6699c65..d4c7e0f 100644 --- a/lib/Frontend/TextDiagnosticPrinter.cpp +++ b/lib/Frontend/TextDiagnosticPrinter.cpp @@ -640,9 +640,18 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level, SourceLocation B = Info.getRange(i).getBegin(); SourceLocation E = Info.getRange(i).getEnd(); - std::pair<FileID, unsigned> BInfo=SM.getDecomposedInstantiationLoc(B); - + B = SM.getInstantiationLoc(B); E = SM.getInstantiationLoc(E); + + // If the End location and the start location are the same and are a + // macro location, then the range was something that came from a macro + // expansion or _Pragma. If this is an object-like macro, the best we + // can do is to highlight the range. If this is a function-like + // macro, we'd also like to highlight the arguments. + if (B == E && Info.getRange(i).getEnd().isMacroID()) + E = SM.getInstantiationRange(Info.getRange(i).getEnd()).second; + + std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(B); std::pair<FileID, unsigned> EInfo = SM.getDecomposedLoc(E); // If the start or end of the range is in another file, just discard diff --git a/lib/Frontend/TypeXML.cpp b/lib/Frontend/TypeXML.cpp new file mode 100644 index 0000000..f32fbbd --- /dev/null +++ b/lib/Frontend/TypeXML.cpp @@ -0,0 +1,127 @@ +//===--- DocumentXML.cpp - XML document for ASTs --------------------------===// +// +// 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 XML document class, which provides the means to +// dump out the AST in a XML form that exposes type details and other fields. +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/DocumentXML.h" +#include "clang/AST/TypeVisitor.h" +#include "clang/AST/Type.h" +#include "clang/AST/Decl.h" + +namespace clang { + namespace XML { + namespace { + +//--------------------------------------------------------- +class TypeWriter : public TypeVisitor<TypeWriter> +{ + DocumentXML& Doc; + +public: + TypeWriter(DocumentXML& doc) : Doc(doc) {} + +#define NODE_XML( CLASS, NAME ) \ + void Visit##CLASS(CLASS* T) \ + { \ + Doc.addSubNode(NAME); + +#define ID_ATTRIBUTE_XML // done by the Document class itself +#define ATTRIBUTE_XML( FN, NAME ) Doc.addAttribute(NAME, T->FN); +#define TYPE_ATTRIBUTE_XML( FN ) ATTRIBUTE_XML(FN, "type") +#define CONTEXT_ATTRIBUTE_XML( FN ) ATTRIBUTE_XML(FN, "context") +#define ATTRIBUTE_OPT_XML( FN, NAME ) Doc.addAttributeOptional(NAME, T->FN); + +#define ATTRIBUTE_ENUM_XML( FN, NAME ) \ + { \ + const char* pAttributeName = NAME; \ + const bool optional = false; \ + switch (T->FN) { \ + default: assert(0 && "unknown enum value"); + +#define ATTRIBUTE_ENUM_OPT_XML( FN, NAME ) \ + { \ + const char* pAttributeName = NAME; \ + const bool optional = true; \ + switch (T->FN) { \ + default: assert(0 && "unknown enum value"); + +#define ENUM_XML( VALUE, NAME ) case VALUE: if ((!optional) || NAME[0]) Doc.addAttribute(pAttributeName, NAME); break; +#define END_ENUM_XML } } +#define END_NODE_XML } + +#include "clang/Frontend/TypeXML.def" + +}; + +//--------------------------------------------------------- + } // anon clang + } // NS XML + +//--------------------------------------------------------- +class DocumentXML::TypeAdder : public TypeVisitor<DocumentXML::TypeAdder> +{ + DocumentXML& Doc; + + void addIfType(const Type* pType) + { + Doc.addTypeRecursively(pType); + } + + void addIfType(const QualType& pType) + { + Doc.addTypeRecursively(pType); + } + + template<class T> void addIfType(T) {} + +public: + TypeAdder(DocumentXML& doc) : Doc(doc) {} + +#define NODE_XML( CLASS, NAME ) \ + void Visit##CLASS(CLASS* T) \ + { + +#define ID_ATTRIBUTE_XML +#define TYPE_ATTRIBUTE_XML( FN ) Doc.addTypeRecursively(T->FN); +#define CONTEXT_ATTRIBUTE_XML( FN ) +#define ATTRIBUTE_XML( FN, NAME ) addIfType(T->FN); +#define ATTRIBUTE_OPT_XML( FN, NAME ) +#define ATTRIBUTE_ENUM_XML( FN, NAME ) +#define ATTRIBUTE_ENUM_OPT_XML( FN, NAME ) +#define ENUM_XML( VALUE, NAME ) +#define END_ENUM_XML +#define END_NODE_XML } + +#include "clang/Frontend/TypeXML.def" +}; + +//--------------------------------------------------------- +void DocumentXML::addParentTypes(const Type* pType) +{ + TypeAdder(*this).Visit(const_cast<Type*>(pType)); +} + +//--------------------------------------------------------- +void DocumentXML::writeTypeToXML(const Type* pType) +{ + XML::TypeWriter(*this).Visit(const_cast<Type*>(pType)); +} + +//--------------------------------------------------------- +void DocumentXML::writeTypeToXML(const QualType& pType) +{ + XML::TypeWriter(*this).VisitQualType(const_cast<QualType*>(&pType)); +} + +//--------------------------------------------------------- +} // NS clang + |