void RewriteBlocks::RewriteBlockPointerFunctionArgs(FunctionDecl *FD) { SourceLocation DeclLoc = FD->getLocation(); unsigned parenCount = 0; // We have 1 or more arguments that have closure pointers. const char *startBuf = SM->getCharacterData(DeclLoc); const char *startArgList = strchr(startBuf, '('); assert((*startArgList == '(') && "Rewriter fuzzy parser confused"); parenCount++; // advance the location to startArgList. DeclLoc = DeclLoc.getFileLocWithOffset(startArgList-startBuf); assert((DeclLoc.isValid()) && "Invalid DeclLoc"); const char *argPtr = startArgList; while (*argPtr++ && parenCount) { switch (*argPtr) { case '^': // Replace the '^' with '*'. DeclLoc = DeclLoc.getFileLocWithOffset(argPtr-startArgList); ReplaceText(DeclLoc, 1, "*", 1); break; case '(': parenCount++; break; case ')': parenCount--; break; } } return; }
Stmt *RewritePRET::RewritePRETTryStmt(PRETTryStmt *S) { //printf("Rewriting a PRET tryin statment.\n"); SourceLocation startLoc = S->getLocStart(); const char *startBuf = SM->getCharacterData(startLoc); std::string buf; std::string deadreg; S->setDeadlineRegister(CurrentDeadlineRegister); CurrentDeadlineRegister++; deadreg = '0' + S->getDeadlineRegister(); buf += "if (_setjmp(PRET_jmpbuf_" + deadreg + ") == 0) /* tryin block */ {\n"; buf += "DEADLOADBRANCH" + deadreg; // Argument to tryin block actually goes to DEADBRANCH statement const char *lParenLoc = strchr(startBuf, '('); ReplaceText(startLoc, lParenLoc-startBuf, buf.c_str(), buf.size()); // Add in if and setjmp code startLoc = S->getTryBlock()->getLocStart(); buf = ";"; ReplaceText(startLoc, 1, buf.c_str(), buf.size()); // Add DEADEND at end of try block startLoc = S->getTryBlock()->getLocEnd(); startBuf = SM->getCharacterData(startLoc); assert((*startBuf == '}') && "bogus tryin block"); buf = "DEADLOAD" + deadreg + "(0);\n"; InsertText(startLoc, buf.c_str(), buf.size()); // Replace catch stament with an else statment startLoc = startLoc.getFileLocWithOffset(1); buf = " else /* catch block */ "; const char *lBraceLoc = strchr(startBuf, '{'); ReplaceText(startLoc, lBraceLoc-startBuf-1, buf.c_str(), buf.size()); return S; }
void RewriteBlocks::RewriteBlockPointerDecl(NamedDecl *ND) { if (FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) { RewriteBlockPointerFunctionArgs(FD); return; } // Handle Variables and Typedefs. SourceLocation DeclLoc = ND->getLocation(); QualType DeclT; if (VarDecl *VD = dyn_cast<VarDecl>(ND)) DeclT = VD->getType(); else if (TypedefDecl *TDD = dyn_cast<TypedefDecl>(ND)) DeclT = TDD->getUnderlyingType(); else if (FieldDecl *FD = dyn_cast<FieldDecl>(ND)) DeclT = FD->getType(); else assert(0 && "RewriteBlockPointerDecl(): Decl type not yet handled"); const char *startBuf = SM->getCharacterData(DeclLoc); const char *endBuf = startBuf; // scan backward (from the decl location) for the end of the previous decl. while (*startBuf != '^' && *startBuf != ';' && startBuf != MainFileStart) startBuf--; // *startBuf != '^' if we are dealing with a pointer to function that // may take block argument types (which will be handled below). if (*startBuf == '^') { // Replace the '^' with '*', computing a negative offset. DeclLoc = DeclLoc.getFileLocWithOffset(startBuf-endBuf); ReplaceText(DeclLoc, 1, "*", 1); } if (PointerTypeTakesAnyBlockArguments(DeclT)) { // Replace the '^' with '*' for arguments. DeclLoc = ND->getLocation(); startBuf = SM->getCharacterData(DeclLoc); const char *argListBegin, *argListEnd; GetExtentOfArgList(startBuf, argListBegin, argListEnd); while (argListBegin < argListEnd) { if (*argListBegin == '^') { SourceLocation CaretLoc = DeclLoc.getFileLocWithOffset(argListBegin-startBuf); ReplaceText(CaretLoc, 1, "*", 1); } argListBegin++; } } return; }
/// AdvanceToTokenCharacter - Given a location that specifies the start of a /// token, return a new location that specifies a character within the token. SourceLocation Preprocessor::AdvanceToTokenCharacter(SourceLocation TokStart, unsigned CharNo) { // Figure out how many physical characters away the specified instantiation // character is. This needs to take into consideration newlines and // trigraphs. bool Invalid = false; const char *TokPtr = SourceMgr.getCharacterData(TokStart, &Invalid); // If they request the first char of the token, we're trivially done. if (Invalid || (CharNo == 0 && Lexer::isObviouslySimpleCharacter(*TokPtr))) return TokStart; unsigned PhysOffset = 0; // The usual case is that tokens don't contain anything interesting. Skip // over the uninteresting characters. If a token only consists of simple // chars, this method is extremely fast. while (Lexer::isObviouslySimpleCharacter(*TokPtr)) { if (CharNo == 0) return TokStart.getFileLocWithOffset(PhysOffset); ++TokPtr, --CharNo, ++PhysOffset; } // If we have a character that may be a trigraph or escaped newline, use a // lexer to parse it correctly. for (; CharNo; --CharNo) { unsigned Size; Lexer::getCharAndSizeNoWarn(TokPtr, Size, Features); TokPtr += Size; PhysOffset += Size; } // Final detail: if we end up on an escaped newline, we want to return the // location of the actual byte of the token. For example foo\<newline>bar // advanced by 3 should return the location of b, not of \\. One compounding // detail of this is that the escape may be made by a trigraph. if (!Lexer::isObviouslySimpleCharacter(*TokPtr)) PhysOffset += Lexer::SkipEscapedNewLines(TokPtr)-TokPtr; return TokStart.getFileLocWithOffset(PhysOffset); }
Stmt *RewritePRET::RewriteMainBody(Stmt *S) { SourceLocation startLoc = S->getLocStart(); startLoc = startLoc.getFileLocWithOffset(1); std::string buf = ""; for (int i = 0; i < CurrentDeadlineRegister; i++) { buf += "register_jmpbuf("; buf += '0' + i; buf += ", &PRET_jmpbuf_"; buf += '0' + i; buf += ");\n"; } InsertText(startLoc, buf.c_str(), buf.size()); return S; }
void RewriteBlocks::RewriteCastExpr(CastExpr *CE) { SourceLocation LocStart = CE->getLocStart(); SourceLocation LocEnd = CE->getLocEnd(); if (!Rewriter::isRewritable(LocStart) || !Rewriter::isRewritable(LocEnd)) return; const char *startBuf = SM->getCharacterData(LocStart); const char *endBuf = SM->getCharacterData(LocEnd); // advance the location to startArgList. const char *argPtr = startBuf; while (*argPtr++ && (argPtr < endBuf)) { switch (*argPtr) { case '^': // Replace the '^' with '*'. LocStart = LocStart.getFileLocWithOffset(argPtr-startBuf); ReplaceText(LocStart, 1, "*", 1); break; } } return; }
/// ParseDirective - Go through the comment and see if it indicates expected /// diagnostics. If so, then put them in the appropriate directive list. /// static void ParseDirective(const char *CommentStart, unsigned CommentLen, ExpectedData &ED, Preprocessor &PP, SourceLocation Pos) { // A single comment may contain multiple directives. for (ParseHelper PH(CommentStart, CommentStart+CommentLen); !PH.Done();) { // search for token: expected if (!PH.Search("expected")) break; PH.Advance(); // next token: - if (!PH.Next("-")) continue; PH.Advance(); // next token: { error | warning | note } DirectiveList* DL = NULL; if (PH.Next("error")) DL = &ED.Errors; else if (PH.Next("warning")) DL = &ED.Warnings; else if (PH.Next("note")) DL = &ED.Notes; else continue; PH.Advance(); // default directive kind bool RegexKind = false; const char* KindStr = "string"; // next optional token: - if (PH.Next("-re")) { PH.Advance(); RegexKind = true; KindStr = "regex"; } // skip optional whitespace PH.SkipWhitespace(); // next optional token: positive integer unsigned Count = 1; if (PH.Next(Count)) PH.Advance(); // skip optional whitespace PH.SkipWhitespace(); // next token: {{ if (!PH.Next("{{")) { PP.Diag(Pos.getFileLocWithOffset(PH.C-PH.Begin), diag::err_verify_missing_start) << KindStr; continue; } PH.Advance(); const char* const ContentBegin = PH.C; // mark content begin // search for token: }} if (!PH.Search("}}")) { PP.Diag(Pos.getFileLocWithOffset(PH.C-PH.Begin), diag::err_verify_missing_end) << KindStr; continue; } const char* const ContentEnd = PH.P; // mark content end PH.Advance(); // build directive text; convert \n to newlines std::string Text; llvm::StringRef NewlineStr = "\\n"; llvm::StringRef Content(ContentBegin, ContentEnd-ContentBegin); size_t CPos = 0; size_t FPos; while ((FPos = Content.find(NewlineStr, CPos)) != llvm::StringRef::npos) { Text += Content.substr(CPos, FPos-CPos); Text += '\n'; CPos = FPos + NewlineStr.size(); } if (Text.empty()) Text.assign(ContentBegin, ContentEnd); // construct new directive Directive *D = Directive::Create(RegexKind, Pos, Text, Count); std::string Error; if (D->isValid(Error)) DL->push_back(D); else { PP.Diag(Pos.getFileLocWithOffset(ContentBegin-PH.Begin), diag::err_verify_invalid_content) << KindStr << Error; } } }
/// Finish - This does final analysis of the declspec, rejecting things like /// "_Imaginary" (lacking an FP type). This returns a diagnostic to issue or /// diag::NUM_DIAGNOSTICS if there is no error. After calling this method, /// DeclSpec is guaranteed self-consistent, even if an error occurred. void DeclSpec::Finish(Diagnostic &D, Preprocessor &PP) { // Check the type specifier components first. SourceManager &SrcMgr = PP.getSourceManager(); // signed/unsigned are only valid with int/char/wchar_t. if (TypeSpecSign != TSS_unspecified) { if (TypeSpecType == TST_unspecified) TypeSpecType = TST_int; // unsigned -> unsigned int, signed -> signed int. else if (TypeSpecType != TST_int && TypeSpecType != TST_char && TypeSpecType != TST_wchar) { Diag(D, TSSLoc, SrcMgr, diag::err_invalid_sign_spec) << getSpecifierName((TST)TypeSpecType); // signed double -> double. TypeSpecSign = TSS_unspecified; } } // Validate the width of the type. switch (TypeSpecWidth) { case TSW_unspecified: break; case TSW_short: // short int case TSW_longlong: // long long int if (TypeSpecType == TST_unspecified) TypeSpecType = TST_int; // short -> short int, long long -> long long int. else if (TypeSpecType != TST_int) { Diag(D, TSWLoc, SrcMgr, TypeSpecWidth == TSW_short ? diag::err_invalid_short_spec : diag::err_invalid_longlong_spec) << getSpecifierName((TST)TypeSpecType); TypeSpecType = TST_int; } break; case TSW_long: // long double, long int if (TypeSpecType == TST_unspecified) TypeSpecType = TST_int; // long -> long int. else if (TypeSpecType != TST_int && TypeSpecType != TST_double) { Diag(D, TSWLoc, SrcMgr, diag::err_invalid_long_spec) << getSpecifierName((TST)TypeSpecType); TypeSpecType = TST_int; } break; } // TODO: if the implementation does not implement _Complex or _Imaginary, // disallow their use. Need information about the backend. if (TypeSpecComplex != TSC_unspecified) { if (TypeSpecType == TST_unspecified) { Diag(D, TSCLoc, SrcMgr, diag::ext_plain_complex) << CodeModificationHint::CreateInsertion( PP.getLocForEndOfToken(getTypeSpecComplexLoc()), " double"); TypeSpecType = TST_double; // _Complex -> _Complex double. } else if (TypeSpecType == TST_int || TypeSpecType == TST_char) { // Note that this intentionally doesn't include _Complex _Bool. Diag(D, TSTLoc, SrcMgr, diag::ext_integer_complex); } else if (TypeSpecType != TST_float && TypeSpecType != TST_double) { Diag(D, TSCLoc, SrcMgr, diag::err_invalid_complex_spec) << getSpecifierName((TST)TypeSpecType); TypeSpecComplex = TSC_unspecified; } } // C++ [class.friend]p6: // No storage-class-specifier shall appear in the decl-specifier-seq // of a friend declaration. if (isFriendSpecified() && getStorageClassSpec()) { DeclSpec::SCS SC = getStorageClassSpec(); const char *SpecName = getSpecifierName(SC); SourceLocation SCLoc = getStorageClassSpecLoc(); SourceLocation SCEndLoc = SCLoc.getFileLocWithOffset(strlen(SpecName)); Diag(D, SCLoc, SrcMgr, diag::err_friend_storage_spec) << SpecName << CodeModificationHint::CreateRemoval(SourceRange(SCLoc, SCEndLoc)); ClearStorageClassSpecs(); } // Okay, now we can infer the real type. // TODO: return "auto function" and other bad things based on the real type. // 'data definition has no type or storage class'? }
/// Finish - This does final analysis of the declspec, rejecting things like /// "_Imaginary" (lacking an FP type). This returns a diagnostic to issue or /// diag::NUM_DIAGNOSTICS if there is no error. After calling this method, /// DeclSpec is guaranteed self-consistent, even if an error occurred. void DeclSpec::Finish(Diagnostic &D, Preprocessor &PP) { // Before possibly changing their values, save specs as written. SaveWrittenBuiltinSpecs(); SaveStorageSpecifierAsWritten(); // Check the type specifier components first. // Validate and finalize AltiVec vector declspec. if (TypeAltiVecVector) { if (TypeAltiVecBool) { // Sign specifiers are not allowed with vector bool. (PIM 2.1) if (TypeSpecSign != TSS_unspecified) { Diag(D, TSSLoc, diag::err_invalid_vector_bool_decl_spec) << getSpecifierName((TSS)TypeSpecSign); } // Only char/int are valid with vector bool. (PIM 2.1) if (((TypeSpecType != TST_unspecified) && (TypeSpecType != TST_char) && (TypeSpecType != TST_int)) || TypeAltiVecPixel) { Diag(D, TSTLoc, diag::err_invalid_vector_bool_decl_spec) << (TypeAltiVecPixel ? "__pixel" : getSpecifierName((TST)TypeSpecType)); } // Only 'short' is valid with vector bool. (PIM 2.1) if ((TypeSpecWidth != TSW_unspecified) && (TypeSpecWidth != TSW_short)) Diag(D, TSWLoc, diag::err_invalid_vector_bool_decl_spec) << getSpecifierName((TSW)TypeSpecWidth); // Elements of vector bool are interpreted as unsigned. (PIM 2.1) if ((TypeSpecType == TST_char) || (TypeSpecType == TST_int) || (TypeSpecWidth != TSW_unspecified)) TypeSpecSign = TSS_unsigned; } if (TypeAltiVecPixel) { //TODO: perform validation TypeSpecType = TST_int; TypeSpecSign = TSS_unsigned; TypeSpecWidth = TSW_short; TypeSpecOwned = false; } } // signed/unsigned are only valid with int/char/wchar_t. if (TypeSpecSign != TSS_unspecified) { if (TypeSpecType == TST_unspecified) TypeSpecType = TST_int; // unsigned -> unsigned int, signed -> signed int. else if (TypeSpecType != TST_int && TypeSpecType != TST_char && TypeSpecType != TST_wchar) { Diag(D, TSSLoc, diag::err_invalid_sign_spec) << getSpecifierName((TST)TypeSpecType); // signed double -> double. TypeSpecSign = TSS_unspecified; } } // Validate the width of the type. switch (TypeSpecWidth) { case TSW_unspecified: break; case TSW_short: // short int case TSW_longlong: // long long int if (TypeSpecType == TST_unspecified) TypeSpecType = TST_int; // short -> short int, long long -> long long int. else if (TypeSpecType != TST_int) { Diag(D, TSWLoc, TypeSpecWidth == TSW_short ? diag::err_invalid_short_spec : diag::err_invalid_longlong_spec) << getSpecifierName((TST)TypeSpecType); TypeSpecType = TST_int; TypeSpecOwned = false; } break; case TSW_long: // long double, long int if (TypeSpecType == TST_unspecified) TypeSpecType = TST_int; // long -> long int. else if (TypeSpecType != TST_int && TypeSpecType != TST_double) { Diag(D, TSWLoc, diag::err_invalid_long_spec) << getSpecifierName((TST)TypeSpecType); TypeSpecType = TST_int; TypeSpecOwned = false; } break; } // TODO: if the implementation does not implement _Complex or _Imaginary, // disallow their use. Need information about the backend. if (TypeSpecComplex != TSC_unspecified) { if (TypeSpecType == TST_unspecified) { Diag(D, TSCLoc, diag::ext_plain_complex) << FixItHint::CreateInsertion( PP.getLocForEndOfToken(getTypeSpecComplexLoc()), " double"); TypeSpecType = TST_double; // _Complex -> _Complex double. } else if (TypeSpecType == TST_int || TypeSpecType == TST_char) { // Note that this intentionally doesn't include _Complex _Bool. Diag(D, TSTLoc, diag::ext_integer_complex); } else if (TypeSpecType != TST_float && TypeSpecType != TST_double) { Diag(D, TSCLoc, diag::err_invalid_complex_spec) << getSpecifierName((TST)TypeSpecType); TypeSpecComplex = TSC_unspecified; } } // C++ [class.friend]p6: // No storage-class-specifier shall appear in the decl-specifier-seq // of a friend declaration. if (isFriendSpecified() && getStorageClassSpec()) { DeclSpec::SCS SC = getStorageClassSpec(); const char *SpecName = getSpecifierName(SC); SourceLocation SCLoc = getStorageClassSpecLoc(); SourceLocation SCEndLoc = SCLoc.getFileLocWithOffset(strlen(SpecName)); Diag(D, SCLoc, diag::err_friend_storage_spec) << SpecName << FixItHint::CreateRemoval(SourceRange(SCLoc, SCEndLoc)); ClearStorageClassSpecs(); } assert(!TypeSpecOwned || isDeclRep((TST) TypeSpecType)); // Okay, now we can infer the real type. // TODO: return "auto function" and other bad things based on the real type. // 'data definition has no type or storage class'? }
void html::AddHeaderFooterInternalBuiltinCSS(Rewriter& R, FileID FID, const char *title) { const llvm::MemoryBuffer *Buf = R.getSourceMgr().getBuffer(FID); const char* FileStart = Buf->getBufferStart(); const char* FileEnd = Buf->getBufferEnd(); SourceLocation StartLoc = R.getSourceMgr().getLocForStartOfFile(FID); SourceLocation EndLoc = StartLoc.getFileLocWithOffset(FileEnd-FileStart); std::string s; llvm::raw_string_ostream os(s); os << "<!doctype html>\n" // Use HTML 5 doctype "<html>\n<head>\n"; if (title) os << "<title>" << html::EscapeText(title) << "</title>\n"; os << "<style type=\"text/css\">\n" " body { color:#000000; background-color:#ffffff }\n" " body { font-family:Helvetica, sans-serif; font-size:10pt }\n" " h1 { font-size:14pt }\n" " .code { border-collapse:collapse; width:100%; }\n" " .code { font-family: \"Andale Mono\", monospace; font-size:10pt }\n" " .code { line-height: 1.2em }\n" " .comment { color: green; font-style: oblique }\n" " .keyword { color: blue }\n" " .string_literal { color: red }\n" " .directive { color: darkmagenta }\n" // Macro expansions. " .expansion { display: none; }\n" " .macro:hover .expansion { display: block; border: 2px solid #FF0000; " "padding: 2px; background-color:#FFF0F0; font-weight: normal; " " -webkit-border-radius:5px; -webkit-box-shadow:1px 1px 7px #000; " "position: absolute; top: -1em; left:10em; z-index: 1 } \n" " .macro { color: darkmagenta; background-color:LemonChiffon;" // Macros are position: relative to provide base for expansions. " position: relative }\n" " .num { width:2.5em; padding-right:2ex; background-color:#eeeeee }\n" " .num { text-align:right; font-size:8pt }\n" " .num { color:#444444 }\n" " .line { padding-left: 1ex; border-left: 3px solid #ccc }\n" " .line { white-space: pre }\n" " .msg { -webkit-box-shadow:1px 1px 7px #000 }\n" " .msg { -webkit-border-radius:5px }\n" " .msg { font-family:Helvetica, sans-serif; font-size:8pt }\n" " .msg { float:left }\n" " .msg { padding:0.25em 1ex 0.25em 1ex }\n" " .msg { margin-top:10px; margin-bottom:10px }\n" " .msg { font-weight:bold }\n" " .msg { max-width:60em; word-wrap: break-word; white-space: pre-wrap }\n" " .msgT { padding:0x; spacing:0x }\n" " .msgEvent { background-color:#fff8b4; color:#000000 }\n" " .msgControl { background-color:#bbbbbb; color:#000000 }\n" " .mrange { background-color:#dfddf3 }\n" " .mrange { border-bottom:1px solid #6F9DBE }\n" " .PathIndex { font-weight: bold; padding:0px 5px 0px 5px; " "margin-right:5px; }\n" " .PathIndex { -webkit-border-radius:8px }\n" " .PathIndexEvent { background-color:#bfba87 }\n" " .PathIndexControl { background-color:#8c8c8c }\n" " .CodeInsertionHint { font-weight: bold; background-color: #10dd10 }\n" " .CodeRemovalHint { background-color:#de1010 }\n" " .CodeRemovalHint { border-bottom:1px solid #6F9DBE }\n" " table.simpletable {\n" " padding: 5px;\n" " font-size:12pt;\n" " margin:20px;\n" " border-collapse: collapse; border-spacing: 0px;\n" " }\n" " td.rowname {\n" " text-align:right; font-weight:bold; color:#444444;\n" " padding-right:2ex; }\n" "</style>\n</head>\n<body>"; // Generate header R.InsertStrBefore(StartLoc, os.str()); // Generate footer R.InsertCStrAfter(EndLoc, "</body></html>\n"); }
void RewriteBlocks::RewriteMethodDecl(ObjCMethodDecl *Method) { bool haveBlockPtrs = false; for (ObjCMethodDecl::param_iterator I = Method->param_begin(), E = Method->param_end(); I != E; ++I) if (isBlockPointerType((*I)->getType())) haveBlockPtrs = true; if (!haveBlockPtrs) return; // Do a fuzzy rewrite. // We have 1 or more arguments that have closure pointers. SourceLocation Loc = Method->getLocStart(); SourceLocation LocEnd = Method->getLocEnd(); const char *startBuf = SM->getCharacterData(Loc); const char *endBuf = SM->getCharacterData(LocEnd); const char *methodPtr = startBuf; std::string Tag = "struct __block_impl *"; while (*methodPtr++ && (methodPtr != endBuf)) { switch (*methodPtr) { case ':': methodPtr++; if (*methodPtr == '(') { const char *scanType = ++methodPtr; bool foundBlockPointer = false; unsigned parenCount = 1; while (parenCount) { switch (*scanType) { case '(': parenCount++; break; case ')': parenCount--; break; case '^': foundBlockPointer = true; break; } scanType++; } if (foundBlockPointer) { // advance the location to startArgList. Loc = Loc.getFileLocWithOffset(methodPtr-startBuf); assert((Loc.isValid()) && "Invalid Loc"); ReplaceText(Loc, scanType-methodPtr-1, Tag.c_str(), Tag.size()); // Advance startBuf. Since the underlying buffer has changed, // it's very important to advance startBuf (so we can correctly // compute a relative Loc the next time around). startBuf = methodPtr; } // Advance the method ptr to the end of the type. methodPtr = scanType; } break; } } return; }