cb424d7448
verify-patch-sanity.py validates every active recipe .patch has internally- consistent hunk line counts — catching the 'malformed patch at line N' failure at commit/CI/preflight time instead of hours into a cook. This cycle hit that class three times (qtwaylandscanner, sddm, xwayland), each only discovered when cookbook tried to apply the patch. Running it across the repo found 29 latent malformed patches (validated against GNU patch: e.g. relibc/P3-sysv-ipc reproduces 'malformed patch at line 22'). They were harmless only because they sit in vendored recipes (baked, not re- applied) — but would fail on any version-bump re-derivation. --fix recounts the hunk headers (body untouched) and repaired all 29. Wired into build-preflight.sh (Phase 1.0D) and redbear-ci.yml, with a unit test (test-patch-sanity.sh). Skips archived/legacy trees and unvalidatable formats (empty placeholders, bare-@@ git hunks).
409 lines
12 KiB
C++
409 lines
12 KiB
C++
//===- CXComment.cpp - libclang APIs for manipulating CXComments ----------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file defines all libclang APIs related to walking comment AST.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "CXComment.h"
|
|
#include "CXCursor.h"
|
|
#include "CXString.h"
|
|
#include "clang-c/Documentation.h"
|
|
#include "clang-c/Index.h"
|
|
#include "clang/AST/Decl.h"
|
|
#include "clang/Index/CommentToXML.h"
|
|
#include "llvm/ADT/StringExtras.h"
|
|
#include "llvm/Support/ErrorHandling.h"
|
|
#include <climits>
|
|
|
|
using namespace clang;
|
|
using namespace clang::comments;
|
|
using namespace clang::cxcomment;
|
|
|
|
CXComment clang_Cursor_getParsedComment(CXCursor C) {
|
|
using namespace clang::cxcursor;
|
|
|
|
if (!clang_isDeclaration(C.kind))
|
|
return createCXComment(nullptr, nullptr);
|
|
|
|
const Decl *D = getCursorDecl(C);
|
|
const ASTContext &Context = getCursorContext(C);
|
|
const FullComment *FC = Context.getCommentForDecl(D, /*PP=*/nullptr);
|
|
|
|
return createCXComment(FC, getCursorTU(C));
|
|
}
|
|
|
|
enum CXCommentKind clang_Comment_getKind(CXComment CXC) {
|
|
const Comment *C = getASTNode(CXC);
|
|
if (!C)
|
|
return CXComment_Null;
|
|
|
|
switch (C->getCommentKind()) {
|
|
case CommentKind::None:
|
|
return CXComment_Null;
|
|
|
|
case CommentKind::TextComment:
|
|
return CXComment_Text;
|
|
|
|
case CommentKind::InlineCommandComment:
|
|
return CXComment_InlineCommand;
|
|
|
|
case CommentKind::HTMLStartTagComment:
|
|
return CXComment_HTMLStartTag;
|
|
|
|
case CommentKind::HTMLEndTagComment:
|
|
return CXComment_HTMLEndTag;
|
|
|
|
case CommentKind::ParagraphComment:
|
|
return CXComment_Paragraph;
|
|
|
|
case CommentKind::BlockCommandComment:
|
|
return CXComment_BlockCommand;
|
|
|
|
case CommentKind::ParamCommandComment:
|
|
return CXComment_ParamCommand;
|
|
|
|
case CommentKind::TParamCommandComment:
|
|
return CXComment_TParamCommand;
|
|
|
|
case CommentKind::VerbatimBlockComment:
|
|
return CXComment_VerbatimBlockCommand;
|
|
|
|
case CommentKind::VerbatimBlockLineComment:
|
|
return CXComment_VerbatimBlockLine;
|
|
|
|
case CommentKind::VerbatimLineComment:
|
|
return CXComment_VerbatimLine;
|
|
|
|
case CommentKind::FullComment:
|
|
return CXComment_FullComment;
|
|
}
|
|
llvm_unreachable("unknown CommentKind");
|
|
}
|
|
|
|
unsigned clang_Comment_getNumChildren(CXComment CXC) {
|
|
const Comment *C = getASTNode(CXC);
|
|
if (!C)
|
|
return 0;
|
|
|
|
return C->child_count();
|
|
}
|
|
|
|
CXComment clang_Comment_getChild(CXComment CXC, unsigned ChildIdx) {
|
|
const Comment *C = getASTNode(CXC);
|
|
if (!C || ChildIdx >= C->child_count())
|
|
return createCXComment(nullptr, nullptr);
|
|
|
|
return createCXComment(*(C->child_begin() + ChildIdx), CXC.TranslationUnit);
|
|
}
|
|
|
|
unsigned clang_Comment_isWhitespace(CXComment CXC) {
|
|
const Comment *C = getASTNode(CXC);
|
|
if (!C)
|
|
return false;
|
|
|
|
if (const TextComment *TC = dyn_cast<TextComment>(C))
|
|
return TC->isWhitespace();
|
|
|
|
if (const ParagraphComment *PC = dyn_cast<ParagraphComment>(C))
|
|
return PC->isWhitespace();
|
|
|
|
return false;
|
|
}
|
|
|
|
unsigned clang_InlineContentComment_hasTrailingNewline(CXComment CXC) {
|
|
const InlineContentComment *ICC = getASTNodeAs<InlineContentComment>(CXC);
|
|
if (!ICC)
|
|
return false;
|
|
|
|
return ICC->hasTrailingNewline();
|
|
}
|
|
|
|
CXString clang_TextComment_getText(CXComment CXC) {
|
|
const TextComment *TC = getASTNodeAs<TextComment>(CXC);
|
|
if (!TC)
|
|
return cxstring::createNull();
|
|
|
|
return cxstring::createRef(TC->getText());
|
|
}
|
|
|
|
CXString clang_InlineCommandComment_getCommandName(CXComment CXC) {
|
|
const InlineCommandComment *ICC = getASTNodeAs<InlineCommandComment>(CXC);
|
|
if (!ICC)
|
|
return cxstring::createNull();
|
|
|
|
const CommandTraits &Traits = getCommandTraits(CXC);
|
|
return cxstring::createRef(ICC->getCommandName(Traits));
|
|
}
|
|
|
|
enum CXCommentInlineCommandRenderKind
|
|
clang_InlineCommandComment_getRenderKind(CXComment CXC) {
|
|
const InlineCommandComment *ICC = getASTNodeAs<InlineCommandComment>(CXC);
|
|
if (!ICC)
|
|
return CXCommentInlineCommandRenderKind_Normal;
|
|
|
|
switch (ICC->getRenderKind()) {
|
|
case InlineCommandRenderKind::Normal:
|
|
return CXCommentInlineCommandRenderKind_Normal;
|
|
|
|
case InlineCommandRenderKind::Bold:
|
|
return CXCommentInlineCommandRenderKind_Bold;
|
|
|
|
case InlineCommandRenderKind::Monospaced:
|
|
return CXCommentInlineCommandRenderKind_Monospaced;
|
|
|
|
case InlineCommandRenderKind::Emphasized:
|
|
return CXCommentInlineCommandRenderKind_Emphasized;
|
|
|
|
case InlineCommandRenderKind::Anchor:
|
|
return CXCommentInlineCommandRenderKind_Anchor;
|
|
}
|
|
llvm_unreachable("unknown InlineCommandComment::RenderKind");
|
|
}
|
|
|
|
unsigned clang_InlineCommandComment_getNumArgs(CXComment CXC) {
|
|
const InlineCommandComment *ICC = getASTNodeAs<InlineCommandComment>(CXC);
|
|
if (!ICC)
|
|
return 0;
|
|
|
|
return ICC->getNumArgs();
|
|
}
|
|
|
|
CXString clang_InlineCommandComment_getArgText(CXComment CXC,
|
|
unsigned ArgIdx) {
|
|
const InlineCommandComment *ICC = getASTNodeAs<InlineCommandComment>(CXC);
|
|
if (!ICC || ArgIdx >= ICC->getNumArgs())
|
|
return cxstring::createNull();
|
|
|
|
return cxstring::createRef(ICC->getArgText(ArgIdx));
|
|
}
|
|
|
|
CXString clang_HTMLTagComment_getTagName(CXComment CXC) {
|
|
const HTMLTagComment *HTC = getASTNodeAs<HTMLTagComment>(CXC);
|
|
if (!HTC)
|
|
return cxstring::createNull();
|
|
|
|
return cxstring::createRef(HTC->getTagName());
|
|
}
|
|
|
|
unsigned clang_HTMLStartTagComment_isSelfClosing(CXComment CXC) {
|
|
const HTMLStartTagComment *HST = getASTNodeAs<HTMLStartTagComment>(CXC);
|
|
if (!HST)
|
|
return false;
|
|
|
|
return HST->isSelfClosing();
|
|
}
|
|
|
|
unsigned clang_HTMLStartTag_getNumAttrs(CXComment CXC) {
|
|
const HTMLStartTagComment *HST = getASTNodeAs<HTMLStartTagComment>(CXC);
|
|
if (!HST)
|
|
return 0;
|
|
|
|
return HST->getNumAttrs();
|
|
}
|
|
|
|
CXString clang_HTMLStartTag_getAttrName(CXComment CXC, unsigned AttrIdx) {
|
|
const HTMLStartTagComment *HST = getASTNodeAs<HTMLStartTagComment>(CXC);
|
|
if (!HST || AttrIdx >= HST->getNumAttrs())
|
|
return cxstring::createNull();
|
|
|
|
return cxstring::createRef(HST->getAttr(AttrIdx).Name);
|
|
}
|
|
|
|
CXString clang_HTMLStartTag_getAttrValue(CXComment CXC, unsigned AttrIdx) {
|
|
const HTMLStartTagComment *HST = getASTNodeAs<HTMLStartTagComment>(CXC);
|
|
if (!HST || AttrIdx >= HST->getNumAttrs())
|
|
return cxstring::createNull();
|
|
|
|
return cxstring::createRef(HST->getAttr(AttrIdx).Value);
|
|
}
|
|
|
|
CXString clang_BlockCommandComment_getCommandName(CXComment CXC) {
|
|
const BlockCommandComment *BCC = getASTNodeAs<BlockCommandComment>(CXC);
|
|
if (!BCC)
|
|
return cxstring::createNull();
|
|
|
|
const CommandTraits &Traits = getCommandTraits(CXC);
|
|
return cxstring::createRef(BCC->getCommandName(Traits));
|
|
}
|
|
|
|
unsigned clang_BlockCommandComment_getNumArgs(CXComment CXC) {
|
|
const BlockCommandComment *BCC = getASTNodeAs<BlockCommandComment>(CXC);
|
|
if (!BCC)
|
|
return 0;
|
|
|
|
return BCC->getNumArgs();
|
|
}
|
|
|
|
CXString clang_BlockCommandComment_getArgText(CXComment CXC,
|
|
unsigned ArgIdx) {
|
|
const BlockCommandComment *BCC = getASTNodeAs<BlockCommandComment>(CXC);
|
|
if (!BCC || ArgIdx >= BCC->getNumArgs())
|
|
return cxstring::createNull();
|
|
|
|
return cxstring::createRef(BCC->getArgText(ArgIdx));
|
|
}
|
|
|
|
CXComment clang_BlockCommandComment_getParagraph(CXComment CXC) {
|
|
const BlockCommandComment *BCC = getASTNodeAs<BlockCommandComment>(CXC);
|
|
if (!BCC)
|
|
return createCXComment(nullptr, nullptr);
|
|
|
|
return createCXComment(BCC->getParagraph(), CXC.TranslationUnit);
|
|
}
|
|
|
|
CXString clang_ParamCommandComment_getParamName(CXComment CXC) {
|
|
const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC);
|
|
if (!PCC || !PCC->hasParamName())
|
|
return cxstring::createNull();
|
|
|
|
return cxstring::createRef(PCC->getParamNameAsWritten());
|
|
}
|
|
|
|
unsigned clang_ParamCommandComment_isParamIndexValid(CXComment CXC) {
|
|
const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC);
|
|
if (!PCC)
|
|
return false;
|
|
|
|
return PCC->isParamIndexValid();
|
|
}
|
|
|
|
unsigned clang_ParamCommandComment_getParamIndex(CXComment CXC) {
|
|
const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC);
|
|
if (!PCC || !PCC->isParamIndexValid() || PCC->isVarArgParam())
|
|
return ParamCommandComment::InvalidParamIndex;
|
|
|
|
return PCC->getParamIndex();
|
|
}
|
|
|
|
unsigned clang_ParamCommandComment_isDirectionExplicit(CXComment CXC) {
|
|
const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC);
|
|
if (!PCC)
|
|
return false;
|
|
|
|
return PCC->isDirectionExplicit();
|
|
}
|
|
|
|
enum CXCommentParamPassDirection clang_ParamCommandComment_getDirection(
|
|
CXComment CXC) {
|
|
const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC);
|
|
if (!PCC)
|
|
return CXCommentParamPassDirection_In;
|
|
|
|
switch (PCC->getDirection()) {
|
|
case ParamCommandPassDirection::In:
|
|
return CXCommentParamPassDirection_In;
|
|
|
|
case ParamCommandPassDirection::Out:
|
|
return CXCommentParamPassDirection_Out;
|
|
|
|
case ParamCommandPassDirection::InOut:
|
|
return CXCommentParamPassDirection_InOut;
|
|
}
|
|
llvm_unreachable("unknown ParamCommandComment::PassDirection");
|
|
}
|
|
|
|
CXString clang_TParamCommandComment_getParamName(CXComment CXC) {
|
|
const TParamCommandComment *TPCC = getASTNodeAs<TParamCommandComment>(CXC);
|
|
if (!TPCC || !TPCC->hasParamName())
|
|
return cxstring::createNull();
|
|
|
|
return cxstring::createRef(TPCC->getParamNameAsWritten());
|
|
}
|
|
|
|
unsigned clang_TParamCommandComment_isParamPositionValid(CXComment CXC) {
|
|
const TParamCommandComment *TPCC = getASTNodeAs<TParamCommandComment>(CXC);
|
|
if (!TPCC)
|
|
return false;
|
|
|
|
return TPCC->isPositionValid();
|
|
}
|
|
|
|
unsigned clang_TParamCommandComment_getDepth(CXComment CXC) {
|
|
const TParamCommandComment *TPCC = getASTNodeAs<TParamCommandComment>(CXC);
|
|
if (!TPCC || !TPCC->isPositionValid())
|
|
return 0;
|
|
|
|
return TPCC->getDepth();
|
|
}
|
|
|
|
unsigned clang_TParamCommandComment_getIndex(CXComment CXC, unsigned Depth) {
|
|
const TParamCommandComment *TPCC = getASTNodeAs<TParamCommandComment>(CXC);
|
|
if (!TPCC || !TPCC->isPositionValid() || Depth >= TPCC->getDepth())
|
|
return 0;
|
|
|
|
return TPCC->getIndex(Depth);
|
|
}
|
|
|
|
CXString clang_VerbatimBlockLineComment_getText(CXComment CXC) {
|
|
const VerbatimBlockLineComment *VBL =
|
|
getASTNodeAs<VerbatimBlockLineComment>(CXC);
|
|
if (!VBL)
|
|
return cxstring::createNull();
|
|
|
|
return cxstring::createRef(VBL->getText());
|
|
}
|
|
|
|
CXString clang_VerbatimLineComment_getText(CXComment CXC) {
|
|
const VerbatimLineComment *VLC = getASTNodeAs<VerbatimLineComment>(CXC);
|
|
if (!VLC)
|
|
return cxstring::createNull();
|
|
|
|
return cxstring::createRef(VLC->getText());
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Converting comments to XML.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
CXString clang_HTMLTagComment_getAsString(CXComment CXC) {
|
|
const HTMLTagComment *HTC = getASTNodeAs<HTMLTagComment>(CXC);
|
|
if (!HTC)
|
|
return cxstring::createNull();
|
|
|
|
CXTranslationUnit TU = CXC.TranslationUnit;
|
|
if (!TU->CommentToXML)
|
|
TU->CommentToXML = new clang::index::CommentToXMLConverter();
|
|
|
|
SmallString<128> Text;
|
|
TU->CommentToXML->convertHTMLTagNodeToText(
|
|
HTC, Text, cxtu::getASTUnit(TU)->getASTContext());
|
|
return cxstring::createDup(Text.str());
|
|
}
|
|
|
|
CXString clang_FullComment_getAsHTML(CXComment CXC) {
|
|
const FullComment *FC = getASTNodeAs<FullComment>(CXC);
|
|
if (!FC)
|
|
return cxstring::createNull();
|
|
|
|
CXTranslationUnit TU = CXC.TranslationUnit;
|
|
if (!TU->CommentToXML)
|
|
TU->CommentToXML = new clang::index::CommentToXMLConverter();
|
|
|
|
SmallString<1024> HTML;
|
|
TU->CommentToXML
|
|
->convertCommentToHTML(FC, HTML, cxtu::getASTUnit(TU)->getASTContext());
|
|
return cxstring::createDup(HTML.str());
|
|
}
|
|
|
|
CXString clang_FullComment_getAsXML(CXComment CXC) {
|
|
const FullComment *FC = getASTNodeAs<FullComment>(CXC);
|
|
if (!FC)
|
|
return cxstring::createNull();
|
|
|
|
CXTranslationUnit TU = CXC.TranslationUnit;
|
|
if (!TU->CommentToXML)
|
|
TU->CommentToXML = new clang::index::CommentToXMLConverter();
|
|
|
|
SmallString<1024> XML;
|
|
TU->CommentToXML
|
|
->convertCommentToXML(FC, XML, cxtu::getASTUnit(TU)->getASTContext());
|
|
return cxstring::createDup(XML.str());
|
|
}
|
|
|