//===--- CommentSema.cpp - Doxygen comment semantic analysis --------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "clang/AST/CommentSema.h" #include "llvm/ADT/StringSwitch.h" namespace clang { namespace comments { Sema::Sema(llvm::BumpPtrAllocator &Allocator) : Allocator(Allocator) { } ParagraphComment *Sema::actOnParagraphComment( ArrayRef Content) { return new (Allocator) ParagraphComment(Content); } BlockCommandComment *Sema::actOnBlockCommandStart(SourceLocation LocBegin, SourceLocation LocEnd, StringRef Name) { return new (Allocator) BlockCommandComment(LocBegin, LocEnd, Name); } BlockCommandComment *Sema::actOnBlockCommandArgs( BlockCommandComment *Command, ArrayRef Args) { Command->setArgs(Args); return Command; } BlockCommandComment *Sema::actOnBlockCommandFinish( BlockCommandComment *Command, ParagraphComment *Paragraph) { Command->setParagraph(Paragraph); return Command; } ParamCommandComment *Sema::actOnParamCommandStart(SourceLocation LocBegin, SourceLocation LocEnd, StringRef Name) { return new (Allocator) ParamCommandComment(LocBegin, LocEnd, Name); } ParamCommandComment *Sema::actOnParamCommandArg(ParamCommandComment *Command, SourceLocation ArgLocBegin, SourceLocation ArgLocEnd, StringRef Arg, bool IsDirection) { if (IsDirection) { ParamCommandComment::PassDirection Direction; std::string ArgLower = Arg.lower(); // TODO: optimize: lower Name first (need an API in SmallString for that), // after that StringSwitch. if (ArgLower == "[in]") Direction = ParamCommandComment::In; else if (ArgLower == "[out]") Direction = ParamCommandComment::Out; else if (ArgLower == "[in,out]" || ArgLower == "[out,in]") Direction = ParamCommandComment::InOut; else { // Remove spaces. std::string::iterator O = ArgLower.begin(); for (std::string::iterator I = ArgLower.begin(), E = ArgLower.end(); I != E; ++I) { const char C = *I; if (C != ' ' && C != '\n' && C != '\r' && C != '\t' && C != '\v' && C != '\f') *O++ = C; } ArgLower.resize(O - ArgLower.begin()); bool RemovingWhitespaceHelped = false; if (ArgLower == "[in]") { Direction = ParamCommandComment::In; RemovingWhitespaceHelped = true; } else if (ArgLower == "[out]") { Direction = ParamCommandComment::Out; RemovingWhitespaceHelped = true; } else if (ArgLower == "[in,out]" || ArgLower == "[out,in]") { Direction = ParamCommandComment::InOut; RemovingWhitespaceHelped = true; } else { Direction = ParamCommandComment::In; RemovingWhitespaceHelped = false; } // Diag() unrecognized parameter passing direction, valid directions are ... // if (RemovingWhitespaceHelped) FixIt } Command->setDirection(Direction, /* Explicit = */ true); } else { if (Command->getArgCount() == 0) { if (!Command->isDirectionExplicit()) { // User didn't provide a direction argument. Command->setDirection(ParamCommandComment::In, /* Explicit = */ false); } typedef BlockCommandComment::Argument Argument; Argument *A = new (Allocator) Argument(SourceRange(ArgLocBegin, ArgLocEnd), Arg); Command->setArgs(llvm::makeArrayRef(A, 1)); // if (...) Diag() unrecognized parameter name } else { // Diag() \\param command requires at most 2 arguments } } return Command; } ParamCommandComment *Sema::actOnParamCommandFinish(ParamCommandComment *Command, ParagraphComment *Paragraph) { Command->setParagraph(Paragraph); return Command; } InlineCommandComment *Sema::actOnInlineCommand(SourceLocation CommandLocBegin, SourceLocation CommandLocEnd, StringRef CommandName) { ArrayRef Args; return new (Allocator) InlineCommandComment(CommandLocBegin, CommandLocEnd, CommandName, Args); } InlineCommandComment *Sema::actOnInlineCommand(SourceLocation CommandLocBegin, SourceLocation CommandLocEnd, StringRef CommandName, SourceLocation ArgLocBegin, SourceLocation ArgLocEnd, StringRef Arg) { typedef InlineCommandComment::Argument Argument; Argument *A = new (Allocator) Argument(SourceRange(ArgLocBegin, ArgLocEnd), Arg); return new (Allocator) InlineCommandComment(CommandLocBegin, CommandLocEnd, CommandName, llvm::makeArrayRef(A, 1)); } InlineContentComment *Sema::actOnUnknownCommand(SourceLocation LocBegin, SourceLocation LocEnd, StringRef Name) { ArrayRef Args; return new (Allocator) InlineCommandComment(LocBegin, LocEnd, Name, Args); } TextComment *Sema::actOnText(SourceLocation LocBegin, SourceLocation LocEnd, StringRef Text) { return new (Allocator) TextComment(LocBegin, LocEnd, Text); } VerbatimBlockComment *Sema::actOnVerbatimBlockStart(SourceLocation Loc, StringRef Name) { return new (Allocator) VerbatimBlockComment( Loc, Loc.getLocWithOffset(1 + Name.size()), Name); } VerbatimBlockLineComment *Sema::actOnVerbatimBlockLine(SourceLocation Loc, StringRef Text) { return new (Allocator) VerbatimBlockLineComment(Loc, Text); } VerbatimBlockComment *Sema::actOnVerbatimBlockFinish( VerbatimBlockComment *Block, SourceLocation CloseNameLocBegin, StringRef CloseName, ArrayRef Lines) { Block->setCloseName(CloseName, CloseNameLocBegin); Block->setLines(Lines); return Block; } VerbatimLineComment *Sema::actOnVerbatimLine(SourceLocation LocBegin, StringRef Name, SourceLocation TextBegin, StringRef Text) { return new (Allocator) VerbatimLineComment( LocBegin, TextBegin.getLocWithOffset(Text.size()), Name, TextBegin, Text); } HTMLOpenTagComment *Sema::actOnHTMLOpenTagStart(SourceLocation LocBegin, StringRef TagName) { return new (Allocator) HTMLOpenTagComment(LocBegin, TagName); } HTMLOpenTagComment *Sema::actOnHTMLOpenTagFinish( HTMLOpenTagComment *Tag, ArrayRef Attrs, SourceLocation GreaterLoc) { Tag->setAttrs(Attrs); Tag->setGreaterLoc(GreaterLoc); return Tag; } HTMLCloseTagComment *Sema::actOnHTMLCloseTag(SourceLocation LocBegin, SourceLocation LocEnd, StringRef TagName) { return new (Allocator) HTMLCloseTagComment(LocBegin, LocEnd, TagName); } FullComment *Sema::actOnFullComment( ArrayRef Blocks) { return new (Allocator) FullComment(Blocks); } // TODO: tablegen bool Sema::isBlockCommand(StringRef Name) { return llvm::StringSwitch(Name) .Case("brief", true) .Case("result", true) .Case("return", true) .Case("returns", true) .Case("author", true) .Case("authors", true) .Case("pre", true) .Case("post", true) .Default(false) || isParamCommand(Name); } bool Sema::isParamCommand(StringRef Name) { return llvm::StringSwitch(Name) .Case("param", true) .Case("arg", true) .Default(false); } unsigned Sema::getBlockCommandNumArgs(StringRef Name) { return llvm::StringSwitch(Name) .Case("brief", 0) .Case("pre", 0) .Case("post", 0) .Case("author", 0) .Case("authors", 0) .Default(0); } bool Sema::isInlineCommand(StringRef Name) { return llvm::StringSwitch(Name) .Case("c", true) .Case("em", true) .Default(false); } bool Sema::HTMLOpenTagNeedsClosing(StringRef Name) { return llvm::StringSwitch(Name) .Case("br", true) .Default(true); } } // end namespace comments } // end namespace clang