diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/AST/CommentSema.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/AST/CommentSema.cpp | 145 |
1 files changed, 79 insertions, 66 deletions
diff --git a/contrib/llvm/tools/clang/lib/AST/CommentSema.cpp b/contrib/llvm/tools/clang/lib/AST/CommentSema.cpp index e0138d5..1c6222f 100644 --- a/contrib/llvm/tools/clang/lib/AST/CommentSema.cpp +++ b/contrib/llvm/tools/clang/lib/AST/CommentSema.cpp @@ -29,8 +29,7 @@ Sema::Sema(llvm::BumpPtrAllocator &Allocator, const SourceManager &SourceMgr, DiagnosticsEngine &Diags, CommandTraits &Traits, const Preprocessor *PP) : Allocator(Allocator), SourceMgr(SourceMgr), Diags(Diags), Traits(Traits), - PP(PP), ThisDeclInfo(NULL), BriefCommand(NULL), ReturnsCommand(NULL), - HeaderfileCommand(NULL) { + PP(PP), ThisDeclInfo(NULL), BriefCommand(NULL), HeaderfileCommand(NULL) { } void Sema::setDecl(const Decl *D) { @@ -99,10 +98,10 @@ void Sema::checkFunctionDeclVerbatimLine(const BlockCommandComment *Comment) { unsigned DiagSelect; switch (Comment->getCommandID()) { case CommandTraits::KCI_function: - DiagSelect = !isAnyFunctionDecl() ? 1 : 0; + DiagSelect = (!isAnyFunctionDecl() && !isFunctionTemplateDecl())? 1 : 0; break; case CommandTraits::KCI_functiongroup: - DiagSelect = !isAnyFunctionDecl() ? 2 : 0; + DiagSelect = (!isAnyFunctionDecl() && !isFunctionTemplateDecl())? 2 : 0; break; case CommandTraits::KCI_method: DiagSelect = !isObjCMethodDecl() ? 3 : 0; @@ -131,7 +130,12 @@ void Sema::checkContainerDeclVerbatimLine(const BlockCommandComment *Comment) { unsigned DiagSelect; switch (Comment->getCommandID()) { case CommandTraits::KCI_class: - DiagSelect = !isClassOrStructDecl() ? 1 : 0; + DiagSelect = (!isClassOrStructDecl() && !isClassTemplateDecl()) ? 1 : 0; + // Allow @class command on @interface declarations. + // FIXME. Currently, \class and @class are indistinguishable. So, + // \class is also allowed on an @interface declaration + if (DiagSelect && Comment->getCommandMarker() && isObjCInterfaceDecl()) + DiagSelect = 0; break; case CommandTraits::KCI_interface: DiagSelect = !isObjCInterfaceDecl() ? 2 : 0; @@ -206,59 +210,43 @@ void Sema::checkContainerDecl(const BlockCommandComment *Comment) { << Comment->getSourceRange(); } +/// \brief Turn a string into the corresponding PassDirection or -1 if it's not +/// valid. +static int getParamPassDirection(StringRef Arg) { + return llvm::StringSwitch<int>(Arg) + .Case("[in]", ParamCommandComment::In) + .Case("[out]", ParamCommandComment::Out) + .Cases("[in,out]", "[out,in]", ParamCommandComment::InOut) + .Default(-1); +} + void Sema::actOnParamCommandDirectionArg(ParamCommandComment *Command, SourceLocation ArgLocBegin, SourceLocation ArgLocEnd, StringRef Arg) { - 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; - } + int Direction = getParamPassDirection(ArgLower); + + if (Direction == -1) { + // Try again with whitespace removed. + ArgLower.erase( + std::remove_if(ArgLower.begin(), ArgLower.end(), clang::isWhitespace), + ArgLower.end()); + Direction = getParamPassDirection(ArgLower); SourceRange ArgRange(ArgLocBegin, ArgLocEnd); - if (RemovingWhitespaceHelped) + if (Direction != -1) { + const char *FixedName = ParamCommandComment::getDirectionAsString( + (ParamCommandComment::PassDirection)Direction); Diag(ArgLocBegin, diag::warn_doc_param_spaces_in_direction) - << ArgRange - << FixItHint::CreateReplacement( - ArgRange, - ParamCommandComment::getDirectionAsString(Direction)); - else - Diag(ArgLocBegin, diag::warn_doc_param_invalid_direction) - << ArgRange; + << ArgRange << FixItHint::CreateReplacement(ArgRange, FixedName); + } else { + Diag(ArgLocBegin, diag::warn_doc_param_invalid_direction) << ArgRange; + Direction = ParamCommandComment::In; // Sane fall back. + } } - Command->setDirection(Direction, /* Explicit = */ true); + Command->setDirection((ParamCommandComment::PassDirection)Direction, + /*Explicit=*/true); } void Sema::actOnParamCommandParamNameArg(ParamCommandComment *Command, @@ -326,17 +314,15 @@ void Sema::actOnTParamCommandParamNameArg(TParamCommandComment *Command, SmallVector<unsigned, 2> Position; if (resolveTParamReference(Arg, TemplateParameters, &Position)) { Command->setPosition(copyArray(llvm::makeArrayRef(Position))); - llvm::StringMap<TParamCommandComment *>::iterator PrevCommandIt = - TemplateParameterDocs.find(Arg); - if (PrevCommandIt != TemplateParameterDocs.end()) { + TParamCommandComment *&PrevCommand = TemplateParameterDocs[Arg]; + if (PrevCommand) { SourceRange ArgRange(ArgLocBegin, ArgLocEnd); Diag(ArgLocBegin, diag::warn_doc_tparam_duplicate) << Arg << ArgRange; - TParamCommandComment *PrevCommand = PrevCommandIt->second; Diag(PrevCommand->getLocation(), diag::note_doc_tparam_previous) << PrevCommand->getParamNameRange(); } - TemplateParameterDocs[Arg] = Command; + PrevCommand = Command; return; } @@ -511,8 +497,7 @@ HTMLEndTagComment *Sema::actOnHTMLEndTag(SourceLocation LocBegin, } while (!HTMLOpenTags.empty()) { - const HTMLStartTagComment *HST = HTMLOpenTags.back(); - HTMLOpenTags.pop_back(); + const HTMLStartTagComment *HST = HTMLOpenTags.pop_back_val(); StringRef LastNotClosedTagName = HST->getTagName(); if (LastNotClosedTagName == TagName) break; @@ -618,12 +603,6 @@ void Sema::checkBlockCommandDuplicate(const BlockCommandComment *Command) { return; } PrevCommand = BriefCommand; - } else if (Info->IsReturnsCommand) { - if (!ReturnsCommand) { - ReturnsCommand = Command; - return; - } - PrevCommand = ReturnsCommand; } else if (Info->IsHeaderfileCommand) { if (!HeaderfileCommand) { HeaderfileCommand = Command; @@ -728,6 +707,10 @@ void Sema::resolveParamCommandIndexes(const FullComment *FC) { // Check that referenced parameter name is in the function decl. const unsigned ResolvedParamIndex = resolveParmVarReference(ParamName, ParamVars); + if (ResolvedParamIndex == ParamCommandComment::VarArgParamIndex) { + PCC->setIsVarArgParam(); + continue; + } if (ResolvedParamIndex == ParamCommandComment::InvalidParamIndex) { UnresolvedParamCommands.push_back(PCC); continue; @@ -798,14 +781,24 @@ bool Sema::isAnyFunctionDecl() { return isFunctionDecl() && ThisDeclInfo->CurrentDecl && isa<FunctionDecl>(ThisDeclInfo->CurrentDecl); } - + +bool Sema::isFunctionOrMethodVariadic() { + if (!isAnyFunctionDecl() && !isObjCMethodDecl()) + return false; + if (const FunctionDecl *FD = + dyn_cast<FunctionDecl>(ThisDeclInfo->CurrentDecl)) + return FD->isVariadic(); + if (const ObjCMethodDecl *MD = + dyn_cast<ObjCMethodDecl>(ThisDeclInfo->CurrentDecl)) + return MD->isVariadic(); + return false; +} + bool Sema::isObjCMethodDecl() { return isFunctionDecl() && ThisDeclInfo->CurrentDecl && isa<ObjCMethodDecl>(ThisDeclInfo->CurrentDecl); } - -/// isFunctionPointerVarDecl - returns 'true' if declaration is a pointer to -/// function decl. + bool Sema::isFunctionPointerVarDecl() { if (!ThisDeclInfo) return false; @@ -865,6 +858,24 @@ bool Sema::isClassOrStructDecl() { isa<RecordDecl>(ThisDeclInfo->CurrentDecl) && !isUnionDecl(); } + +bool Sema::isClassTemplateDecl() { + if (!ThisDeclInfo) + return false; + if (!ThisDeclInfo->IsFilled) + inspectThisDecl(); + return ThisDeclInfo->CurrentDecl && + (isa<ClassTemplateDecl>(ThisDeclInfo->CurrentDecl)); +} + +bool Sema::isFunctionTemplateDecl() { + if (!ThisDeclInfo) + return false; + if (!ThisDeclInfo->IsFilled) + inspectThisDecl(); + return ThisDeclInfo->CurrentDecl && + (isa<FunctionTemplateDecl>(ThisDeclInfo->CurrentDecl)); +} bool Sema::isObjCInterfaceDecl() { if (!ThisDeclInfo) @@ -901,6 +912,8 @@ unsigned Sema::resolveParmVarReference(StringRef Name, if (II && II->getName() == Name) return i; } + if (Name == "..." && isFunctionOrMethodVariadic()) + return ParamCommandComment::VarArgParamIndex; return ParamCommandComment::InvalidParamIndex; } |