diff options
Diffstat (limited to 'clang-tools-extra')
146 files changed, 3890 insertions, 1521 deletions
diff --git a/clang-tools-extra/clang-apply-replacements/tool/ClangApplyReplacementsMain.cpp b/clang-tools-extra/clang-apply-replacements/tool/ClangApplyReplacementsMain.cpp index 062e236..76de8bd 100644 --- a/clang-tools-extra/clang-apply-replacements/tool/ClangApplyReplacementsMain.cpp +++ b/clang-tools-extra/clang-apply-replacements/tool/ClangApplyReplacementsMain.cpp @@ -97,8 +97,7 @@ int main(int argc, char **argv) { cl::ParseCommandLineOptions(argc, argv); DiagnosticOptions DiagOpts; - DiagnosticsEngine Diagnostics( - IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), DiagOpts); + DiagnosticsEngine Diagnostics(DiagnosticIDs::create(), DiagOpts); // Determine a formatting style from options. auto FormatStyleOrError = format::getStyle(FormatStyleOpt, FormatStyleConfig, diff --git a/clang-tools-extra/clang-change-namespace/tool/ClangChangeNamespace.cpp b/clang-tools-extra/clang-change-namespace/tool/ClangChangeNamespace.cpp index 2a8fe2d..2efdd92 100644 --- a/clang-tools-extra/clang-change-namespace/tool/ClangChangeNamespace.cpp +++ b/clang-tools-extra/clang-change-namespace/tool/ClangChangeNamespace.cpp @@ -128,9 +128,8 @@ int main(int argc, const char **argv) { LangOptions DefaultLangOptions; DiagnosticOptions DiagOpts; clang::TextDiagnosticPrinter DiagnosticPrinter(errs(), DiagOpts); - DiagnosticsEngine Diagnostics( - IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), DiagOpts, - &DiagnosticPrinter, false); + DiagnosticsEngine Diagnostics(DiagnosticIDs::create(), DiagOpts, + &DiagnosticPrinter, false); auto &FileMgr = Tool.getFiles(); SourceManager Sources(Diagnostics, FileMgr); Rewriter Rewrite(Sources, DefaultLangOptions); diff --git a/clang-tools-extra/clang-doc/BitcodeReader.cpp b/clang-tools-extra/clang-doc/BitcodeReader.cpp index dce34a8..4efbbd3 100644 --- a/clang-tools-extra/clang-doc/BitcodeReader.cpp +++ b/clang-tools-extra/clang-doc/BitcodeReader.cpp @@ -384,6 +384,8 @@ static llvm::Error parseRecord(const Record &R, unsigned ID, return decodeRecord(R, I->Path, Blob); case REFERENCE_FIELD: return decodeRecord(R, F, Blob); + case REFERENCE_FILE: + return decodeRecord(R, I->DocumentationFileName, Blob); default: return llvm::createStringError(llvm::inconvertibleErrorCode(), "invalid field for Reference"); diff --git a/clang-tools-extra/clang-doc/BitcodeWriter.cpp b/clang-tools-extra/clang-doc/BitcodeWriter.cpp index eed2372..e23511b 100644 --- a/clang-tools-extra/clang-doc/BitcodeWriter.cpp +++ b/clang-tools-extra/clang-doc/BitcodeWriter.cpp @@ -210,6 +210,7 @@ static const llvm::IndexedMap<RecordIdDsc, RecordIdToIndexFunctor> {REFERENCE_TYPE, {"RefType", &genIntAbbrev}}, {REFERENCE_PATH, {"Path", &genStringAbbrev}}, {REFERENCE_FIELD, {"Field", &genIntAbbrev}}, + {REFERENCE_FILE, {"File", &genStringAbbrev}}, {TEMPLATE_PARAM_CONTENTS, {"Contents", &genStringAbbrev}}, {TEMPLATE_SPECIALIZATION_OF, {"SpecializationOf", &genSymbolIdAbbrev}}, @@ -286,7 +287,7 @@ static const std::vector<std::pair<BlockId, std::vector<RecordId>>> // Reference Block {BI_REFERENCE_BLOCK_ID, {REFERENCE_USR, REFERENCE_NAME, REFERENCE_QUAL_NAME, REFERENCE_TYPE, - REFERENCE_PATH, REFERENCE_FIELD}}, + REFERENCE_PATH, REFERENCE_FIELD, REFERENCE_FILE}}, // Template Blocks. {BI_TEMPLATE_BLOCK_ID, {}}, {BI_TEMPLATE_PARAM_BLOCK_ID, {TEMPLATE_PARAM_CONTENTS}}, @@ -479,6 +480,7 @@ void ClangDocBitcodeWriter::emitBlock(const Reference &R, FieldId Field) { emitRecord((unsigned)R.RefType, REFERENCE_TYPE); emitRecord(R.Path, REFERENCE_PATH); emitRecord((unsigned)Field, REFERENCE_FIELD); + emitRecord(R.DocumentationFileName, REFERENCE_FILE); } void ClangDocBitcodeWriter::emitBlock(const FriendInfo &R) { diff --git a/clang-tools-extra/clang-doc/BitcodeWriter.h b/clang-tools-extra/clang-doc/BitcodeWriter.h index 501af12..688f886 100644 --- a/clang-tools-extra/clang-doc/BitcodeWriter.h +++ b/clang-tools-extra/clang-doc/BitcodeWriter.h @@ -140,6 +140,7 @@ enum RecordId { REFERENCE_TYPE, REFERENCE_PATH, REFERENCE_FIELD, + REFERENCE_FILE, TEMPLATE_PARAM_CONTENTS, TEMPLATE_SPECIALIZATION_OF, TYPEDEF_USR, diff --git a/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp b/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp index 7aeaa1b..a64cb5e 100644 --- a/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp +++ b/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp @@ -27,6 +27,9 @@ using namespace llvm::mustache; namespace clang { namespace doc { +static Error generateDocForJSON(json::Value &JSON, StringRef Filename, + StringRef Path, raw_fd_ostream &OS, + const ClangDocContext &CDCtx); static Error createFileOpenError(StringRef FileName, std::error_code EC) { return createFileError("cannot open file " + FileName, EC); @@ -132,404 +135,68 @@ Error MustacheHTMLGenerator::generateDocs( return Err; } - // Track which directories we already tried to create. - StringSet<> CreatedDirs; - // Collect all output by file name and create the necessary directories. - StringMap<std::vector<doc::Info *>> FileToInfos; - for (const auto &Group : Infos) { - llvm::TimeTraceScope TS("setup directories"); - doc::Info *Info = Group.getValue().get(); - - SmallString<128> Path; - sys::path::native(RootDir, Path); - sys::path::append(Path, Info->getRelativeFilePath("")); - if (!CreatedDirs.contains(Path)) { - if (std::error_code EC = sys::fs::create_directories(Path)) - return createStringError(EC, "failed to create directory '%s'.", - Path.c_str()); - CreatedDirs.insert(Path); - } - - sys::path::append(Path, Info->getFileBaseName() + ".html"); - FileToInfos[Path].push_back(Info); + { + llvm::TimeTraceScope TS("Generate JSON for Mustache"); + if (auto JSONGenerator = findGeneratorByName("json")) { + if (Error Err = JSONGenerator.get()->generateDocs( + RootDir, std::move(Infos), CDCtx)) + return Err; + } else + return JSONGenerator.takeError(); } + StringMap<json::Value> JSONFileMap; { - llvm::TimeTraceScope TS("Generate Docs"); - for (const auto &Group : FileToInfos) { - llvm::TimeTraceScope TS("Info to Doc"); + llvm::TimeTraceScope TS("Iterate JSON files"); + std::error_code EC; + sys::fs::directory_iterator JSONIter(RootDir, EC); + std::vector<json::Value> JSONFiles; + JSONFiles.reserve(Infos.size()); + if (EC) + return createStringError("Failed to create directory iterator."); + + while (JSONIter != sys::fs::directory_iterator()) { + if (EC) + return createFileError("Failed to iterate: " + JSONIter->path(), EC); + + auto Path = StringRef(JSONIter->path()); + if (!Path.ends_with(".json")) { + JSONIter.increment(EC); + continue; + } + + auto File = MemoryBuffer::getFile(Path); + if (EC = File.getError(); EC) + // TODO: Buffer errors to report later, look into using Clang + // diagnostics. + llvm::errs() << "Failed to open file: " << Path << " " << EC.message() + << '\n'; + + auto Parsed = json::parse((*File)->getBuffer()); + if (!Parsed) + return Parsed.takeError(); + std::error_code FileErr; - raw_fd_ostream InfoOS(Group.getKey(), FileErr, sys::fs::OF_None); + SmallString<16> HTMLPath(Path.begin(), Path.end()); + sys::path::replace_extension(HTMLPath, "html"); + raw_fd_ostream InfoOS(HTMLPath, FileErr, sys::fs::OF_None); if (FileErr) - return createFileOpenError(Group.getKey(), FileErr); + return createFileOpenError(Path, FileErr); - for (const auto &Info : Group.getValue()) - if (Error Err = generateDocForInfo(Info, InfoOS, CDCtx)) - return Err; + if (Error Err = generateDocForJSON(*Parsed, sys::path::stem(HTMLPath), + HTMLPath, InfoOS, CDCtx)) + return Err; + JSONIter.increment(EC); } } - return Error::success(); -} - -static json::Value -extractValue(const Location &L, - std::optional<StringRef> RepositoryUrl = std::nullopt) { - Object Obj = Object(); - // TODO: Consider using both Start/End line numbers to improve location report - Obj.insert({"LineNumber", L.StartLineNumber}); - Obj.insert({"Filename", L.Filename}); - - if (!L.IsFileInRootDir || !RepositoryUrl) - return Obj; - SmallString<128> FileURL(*RepositoryUrl); - sys::path::append(FileURL, sys::path::Style::posix, L.Filename); - FileURL += "#" + std::to_string(L.StartLineNumber); - Obj.insert({"FileURL", FileURL}); - - return Obj; -} - -static json::Value extractValue(const Reference &I, - StringRef CurrentDirectory) { - SmallString<64> Path = I.getRelativeFilePath(CurrentDirectory); - sys::path::append(Path, I.getFileBaseName() + ".html"); - sys::path::native(Path, sys::path::Style::posix); - Object Obj = Object(); - Obj.insert({"Link", Path}); - Obj.insert({"Name", I.Name}); - Obj.insert({"QualName", I.QualName}); - Obj.insert({"ID", toHex(toStringRef(I.USR))}); - return Obj; -} - -static json::Value extractValue(const TypedefInfo &I) { - // Not Supported - return nullptr; -} - -static json::Value extractValue(const CommentInfo &I) { - Object Obj = Object(); - - json::Value ChildVal = Object(); - Object &Child = *ChildVal.getAsObject(); - - json::Value ChildArr = Array(); - auto &CARef = *ChildArr.getAsArray(); - CARef.reserve(I.Children.size()); - for (const auto &C : I.Children) - CARef.emplace_back(extractValue(*C)); - - switch (I.Kind) { - case CommentKind::CK_TextComment: { - Obj.insert({commentKindToString(I.Kind), I.Text}); - return Obj; - } - - case CommentKind::CK_BlockCommandComment: { - Child.insert({"Command", I.Name}); - Child.insert({"Children", ChildArr}); - Obj.insert({commentKindToString(I.Kind), ChildVal}); - return Obj; - } - - case CommentKind::CK_InlineCommandComment: { - json::Value ArgsArr = Array(); - auto &ARef = *ArgsArr.getAsArray(); - ARef.reserve(I.Args.size()); - for (const auto &Arg : I.Args) - ARef.emplace_back(Arg); - Child.insert({"Command", I.Name}); - Child.insert({"Args", ArgsArr}); - Child.insert({"Children", ChildArr}); - Obj.insert({commentKindToString(I.Kind), ChildVal}); - return Obj; - } - - case CommentKind::CK_ParamCommandComment: - case CommentKind::CK_TParamCommandComment: { - Child.insert({"ParamName", I.ParamName}); - Child.insert({"Direction", I.Direction}); - Child.insert({"Explicit", I.Explicit}); - Child.insert({"Children", ChildArr}); - Obj.insert({commentKindToString(I.Kind), ChildVal}); - return Obj; - } - - case CommentKind::CK_VerbatimBlockComment: { - Child.insert({"Text", I.Text}); - if (!I.CloseName.empty()) - Child.insert({"CloseName", I.CloseName}); - Child.insert({"Children", ChildArr}); - Obj.insert({commentKindToString(I.Kind), ChildVal}); - return Obj; - } - - case CommentKind::CK_VerbatimBlockLineComment: - case CommentKind::CK_VerbatimLineComment: { - Child.insert({"Text", I.Text}); - Child.insert({"Children", ChildArr}); - Obj.insert({commentKindToString(I.Kind), ChildVal}); - return Obj; - } - - case CommentKind::CK_HTMLStartTagComment: { - json::Value AttrKeysArray = json::Array(); - json::Value AttrValuesArray = json::Array(); - auto &KeyArr = *AttrKeysArray.getAsArray(); - auto &ValArr = *AttrValuesArray.getAsArray(); - KeyArr.reserve(I.AttrKeys.size()); - ValArr.reserve(I.AttrValues.size()); - for (const auto &K : I.AttrKeys) - KeyArr.emplace_back(K); - for (const auto &V : I.AttrValues) - ValArr.emplace_back(V); - Child.insert({"Name", I.Name}); - Child.insert({"SelfClosing", I.SelfClosing}); - Child.insert({"AttrKeys", AttrKeysArray}); - Child.insert({"AttrValues", AttrValuesArray}); - Child.insert({"Children", ChildArr}); - Obj.insert({commentKindToString(I.Kind), ChildVal}); - return Obj; - } - - case CommentKind::CK_HTMLEndTagComment: { - Child.insert({"Name", I.Name}); - Child.insert({"Children", ChildArr}); - Obj.insert({commentKindToString(I.Kind), ChildVal}); - return Obj; - } - - case CommentKind::CK_FullComment: - case CommentKind::CK_ParagraphComment: { - Child.insert({"Children", ChildArr}); - Obj.insert({commentKindToString(I.Kind), ChildVal}); - return Obj; - } - - case CommentKind::CK_Unknown: { - Obj.insert({commentKindToString(I.Kind), I.Text}); - return Obj; - } - } - llvm_unreachable("Unknown comment kind encountered."); -} - -static void maybeInsertLocation(std::optional<Location> Loc, - const ClangDocContext &CDCtx, Object &Obj) { - if (!Loc) - return; - Location L = *Loc; - Obj.insert({"Location", extractValue(L, CDCtx.RepositoryUrl)}); -} - -static void extractDescriptionFromInfo(ArrayRef<CommentInfo> Descriptions, - json::Object &EnumValObj) { - if (Descriptions.empty()) - return; - json::Value DescArr = Array(); - json::Array &DescARef = *DescArr.getAsArray(); - DescARef.reserve(Descriptions.size()); - for (const CommentInfo &Child : Descriptions) - DescARef.emplace_back(extractValue(Child)); - EnumValObj.insert({"EnumValueComments", DescArr}); -} - -static json::Value extractValue(const FunctionInfo &I, StringRef ParentInfoDir, - const ClangDocContext &CDCtx) { - Object Obj = Object(); - Obj.insert({"Name", I.Name}); - Obj.insert({"ID", toHex(toStringRef(I.USR))}); - Obj.insert({"Access", getAccessSpelling(I.Access).str()}); - Obj.insert({"ReturnType", extractValue(I.ReturnType.Type, ParentInfoDir)}); - - json::Value ParamArr = Array(); - json::Array &ParamARef = *ParamArr.getAsArray(); - ParamARef.reserve(I.Params.size()); - for (const auto Val : enumerate(I.Params)) { - json::Value V = Object(); - auto &VRef = *V.getAsObject(); - VRef.insert({"Name", Val.value().Name}); - VRef.insert({"Type", Val.value().Type.Name}); - VRef.insert({"End", Val.index() + 1 == I.Params.size()}); - ParamARef.emplace_back(V); - } - Obj.insert({"Params", ParamArr}); - maybeInsertLocation(I.DefLoc, CDCtx, Obj); - return Obj; -} - -static json::Value extractValue(const EnumInfo &I, - const ClangDocContext &CDCtx) { - Object Obj = Object(); - std::string EnumType = I.Scoped ? "enum class " : "enum "; - EnumType += I.Name; - bool HasComment = llvm::any_of( - I.Members, [](const EnumValueInfo &M) { return !M.Description.empty(); }); - Obj.insert({"EnumName", EnumType}); - Obj.insert({"HasComment", HasComment}); - Obj.insert({"ID", toHex(toStringRef(I.USR))}); - json::Value EnumArr = Array(); - json::Array &EnumARef = *EnumArr.getAsArray(); - EnumARef.reserve(I.Members.size()); - for (const EnumValueInfo &M : I.Members) { - json::Value EnumValue = Object(); - auto &EnumValObj = *EnumValue.getAsObject(); - EnumValObj.insert({"Name", M.Name}); - if (!M.ValueExpr.empty()) - EnumValObj.insert({"ValueExpr", M.ValueExpr}); - else - EnumValObj.insert({"Value", M.Value}); - - extractDescriptionFromInfo(M.Description, EnumValObj); - EnumARef.emplace_back(EnumValue); - } - Obj.insert({"EnumValues", EnumArr}); - - extractDescriptionFromInfo(I.Description, Obj); - maybeInsertLocation(I.DefLoc, CDCtx, Obj); - - return Obj; -} - -static void extractScopeChildren(const ScopeChildren &S, Object &Obj, - StringRef ParentInfoDir, - const ClangDocContext &CDCtx) { - json::Value NamespaceArr = Array(); - json::Array &NamespaceARef = *NamespaceArr.getAsArray(); - NamespaceARef.reserve(S.Namespaces.size()); - for (const Reference &Child : S.Namespaces) - NamespaceARef.emplace_back(extractValue(Child, ParentInfoDir)); - - if (!NamespaceARef.empty()) - Obj.insert({"Namespace", Object{{"Links", NamespaceArr}}}); - - json::Value RecordArr = Array(); - json::Array &RecordARef = *RecordArr.getAsArray(); - RecordARef.reserve(S.Records.size()); - for (const Reference &Child : S.Records) - RecordARef.emplace_back(extractValue(Child, ParentInfoDir)); - - if (!RecordARef.empty()) - Obj.insert({"Record", Object{{"Links", RecordArr}}}); - - json::Value FunctionArr = Array(); - json::Array &FunctionARef = *FunctionArr.getAsArray(); - FunctionARef.reserve(S.Functions.size()); - - json::Value PublicFunctionArr = Array(); - json::Array &PublicFunctionARef = *PublicFunctionArr.getAsArray(); - PublicFunctionARef.reserve(S.Functions.size()); - - json::Value ProtectedFunctionArr = Array(); - json::Array &ProtectedFunctionARef = *ProtectedFunctionArr.getAsArray(); - ProtectedFunctionARef.reserve(S.Functions.size()); - - for (const FunctionInfo &Child : S.Functions) { - json::Value F = extractValue(Child, ParentInfoDir, CDCtx); - AccessSpecifier Access = Child.Access; - if (Access == AccessSpecifier::AS_public) - PublicFunctionARef.emplace_back(F); - else if (Access == AccessSpecifier::AS_protected) - ProtectedFunctionARef.emplace_back(F); - else - FunctionARef.emplace_back(F); - } - - if (!FunctionARef.empty()) - Obj.insert({"Function", Object{{"Obj", FunctionArr}}}); - - if (!PublicFunctionARef.empty()) - Obj.insert({"PublicFunction", Object{{"Obj", PublicFunctionArr}}}); - - if (!ProtectedFunctionARef.empty()) - Obj.insert({"ProtectedFunction", Object{{"Obj", ProtectedFunctionArr}}}); - - json::Value EnumArr = Array(); - auto &EnumARef = *EnumArr.getAsArray(); - EnumARef.reserve(S.Enums.size()); - for (const EnumInfo &Child : S.Enums) - EnumARef.emplace_back(extractValue(Child, CDCtx)); - - if (!EnumARef.empty()) - Obj.insert({"Enums", Object{{"Obj", EnumArr}}}); - - json::Value TypedefArr = Array(); - auto &TypedefARef = *TypedefArr.getAsArray(); - TypedefARef.reserve(S.Typedefs.size()); - for (const TypedefInfo &Child : S.Typedefs) - TypedefARef.emplace_back(extractValue(Child)); - - if (!TypedefARef.empty()) - Obj.insert({"Typedefs", Object{{"Obj", TypedefArr}}}); -} - -static json::Value extractValue(const NamespaceInfo &I, - const ClangDocContext &CDCtx) { - Object NamespaceValue = Object(); - std::string InfoTitle = I.Name.empty() ? "Global Namespace" - : (Twine("namespace ") + I.Name).str(); - - SmallString<64> BasePath = I.getRelativeFilePath(""); - NamespaceValue.insert({"NamespaceTitle", InfoTitle}); - NamespaceValue.insert({"NamespacePath", BasePath}); - - extractDescriptionFromInfo(I.Description, NamespaceValue); - extractScopeChildren(I.Children, NamespaceValue, BasePath, CDCtx); - return NamespaceValue; -} - -static json::Value extractValue(const RecordInfo &I, - const ClangDocContext &CDCtx) { - Object RecordValue = Object(); - extractDescriptionFromInfo(I.Description, RecordValue); - RecordValue.insert({"Name", I.Name}); - RecordValue.insert({"FullName", I.FullName}); - RecordValue.insert({"RecordType", getTagType(I.TagType)}); - - maybeInsertLocation(I.DefLoc, CDCtx, RecordValue); - - SmallString<64> BasePath = I.getRelativeFilePath(""); - extractScopeChildren(I.Children, RecordValue, BasePath, CDCtx); - json::Value PublicMembers = Array(); - json::Array &PubMemberRef = *PublicMembers.getAsArray(); - PubMemberRef.reserve(I.Members.size()); - json::Value ProtectedMembers = Array(); - json::Array &ProtMemberRef = *ProtectedMembers.getAsArray(); - ProtMemberRef.reserve(I.Members.size()); - json::Value PrivateMembers = Array(); - json::Array &PrivMemberRef = *PrivateMembers.getAsArray(); - PrivMemberRef.reserve(I.Members.size()); - for (const MemberTypeInfo &Member : I.Members) { - json::Value MemberValue = Object(); - auto &MVRef = *MemberValue.getAsObject(); - MVRef.insert({"Name", Member.Name}); - MVRef.insert({"Type", Member.Type.Name}); - extractDescriptionFromInfo(Member.Description, MVRef); - - if (Member.Access == AccessSpecifier::AS_public) - PubMemberRef.emplace_back(MemberValue); - else if (Member.Access == AccessSpecifier::AS_protected) - ProtMemberRef.emplace_back(MemberValue); - else if (Member.Access == AccessSpecifier::AS_private) - ProtMemberRef.emplace_back(MemberValue); - } - if (!PubMemberRef.empty()) - RecordValue.insert({"PublicMembers", Object{{"Obj", PublicMembers}}}); - if (!ProtMemberRef.empty()) - RecordValue.insert({"ProtectedMembers", Object{{"Obj", ProtectedMembers}}}); - if (!PrivMemberRef.empty()) - RecordValue.insert({"PrivateMembers", Object{{"Obj", PrivateMembers}}}); - - return RecordValue; + return Error::success(); } -static Error setupTemplateValue(const ClangDocContext &CDCtx, json::Value &V, - Info *I) { +static Error setupTemplateValue(const ClangDocContext &CDCtx, json::Value &V) { V.getAsObject()->insert({"ProjectName", CDCtx.ProjectName}); json::Value StylesheetArr = Array(); - auto InfoPath = I->getRelativeFilePath(""); - SmallString<128> RelativePath = computeRelativePath("", InfoPath); + SmallString<128> RelativePath("./"); sys::path::native(RelativePath, sys::path::Style::posix); auto *SSA = StylesheetArr.getAsArray(); @@ -555,38 +222,42 @@ static Error setupTemplateValue(const ClangDocContext &CDCtx, json::Value &V, return Error::success(); } -Error MustacheHTMLGenerator::generateDocForInfo(Info *I, raw_ostream &OS, - const ClangDocContext &CDCtx) { - switch (I->IT) { - case InfoType::IT_namespace: { - json::Value V = - extractValue(*static_cast<clang::doc::NamespaceInfo *>(I), CDCtx); - if (auto Err = setupTemplateValue(CDCtx, V, I)) +static Error generateDocForJSON(json::Value &JSON, StringRef Filename, + StringRef Path, raw_fd_ostream &OS, + const ClangDocContext &CDCtx) { + auto StrValue = (*JSON.getAsObject())["InfoType"]; + if (StrValue.kind() != json::Value::Kind::String) + return createStringError("JSON file '%s' does not contain key: 'InfoType'.", + Filename.str().c_str()); + auto ObjTypeStr = StrValue.getAsString(); + if (!ObjTypeStr.has_value()) + return createStringError( + "JSON file '%s' does not contain 'InfoType' field as a string.", + Filename.str().c_str()); + + if (ObjTypeStr.value() == "namespace") { + if (auto Err = setupTemplateValue(CDCtx, JSON)) return Err; assert(NamespaceTemplate && "NamespaceTemplate is nullptr."); - NamespaceTemplate->render(V, OS); - break; - } - case InfoType::IT_record: { - json::Value V = - extractValue(*static_cast<clang::doc::RecordInfo *>(I), CDCtx); - if (auto Err = setupTemplateValue(CDCtx, V, I)) + NamespaceTemplate->render(JSON, OS); + } else if (ObjTypeStr.value() == "record") { + if (auto Err = setupTemplateValue(CDCtx, JSON)) return Err; - // Serialize the JSON value to the output stream in a readable format. - RecordTemplate->render(V, OS); - break; + assert(RecordTemplate && "RecordTemplate is nullptr."); + RecordTemplate->render(JSON, OS); } + return Error::success(); +} + +Error MustacheHTMLGenerator::generateDocForInfo(Info *I, raw_ostream &OS, + const ClangDocContext &CDCtx) { + switch (I->IT) { case InfoType::IT_enum: - OS << "IT_enum\n"; - break; case InfoType::IT_function: - OS << "IT_Function\n"; - break; case InfoType::IT_typedef: - OS << "IT_typedef\n"; - break; + case InfoType::IT_namespace: + case InfoType::IT_record: case InfoType::IT_concept: - break; case InfoType::IT_variable: case InfoType::IT_friend: break; diff --git a/clang-tools-extra/clang-doc/JSONGenerator.cpp b/clang-tools-extra/clang-doc/JSONGenerator.cpp index cc4c683..599b381 100644 --- a/clang-tools-extra/clang-doc/JSONGenerator.cpp +++ b/clang-tools-extra/clang-doc/JSONGenerator.cpp @@ -43,6 +43,30 @@ static auto SerializeReferenceLambda = [](const auto &Ref, Object &Object) { serializeReference(Ref, Object); }; +static std::string infoTypeToString(InfoType IT) { + switch (IT) { + case InfoType::IT_default: + return "default"; + case InfoType::IT_namespace: + return "namespace"; + case InfoType::IT_record: + return "record"; + case InfoType::IT_function: + return "function"; + case InfoType::IT_enum: + return "enum"; + case InfoType::IT_typedef: + return "typedef"; + case InfoType::IT_concept: + return "concept"; + case InfoType::IT_variable: + return "variable"; + case InfoType::IT_friend: + return "friend"; + } + llvm_unreachable("Unknown InfoType encountered."); +} + static json::Object serializeLocation(const Location &Loc, const std::optional<StringRef> RepositoryUrl) { @@ -59,7 +83,39 @@ serializeLocation(const Location &Loc, return LocationObj; } -static json::Value serializeComment(const CommentInfo &I) { +static void insertComment(Object &Description, json::Value &Comment, + StringRef Key) { + auto DescriptionIt = Description.find(Key); + + if (DescriptionIt == Description.end()) { + auto CommentsArray = json::Array(); + CommentsArray.push_back(Comment); + Description[Key] = std::move(CommentsArray); + Description["Has" + Key.str()] = true; + } else { + DescriptionIt->getSecond().getAsArray()->push_back(Comment); + } +} + +static json::Value extractTextComments(Object *ParagraphComment) { + if (!ParagraphComment) + return json::Object(); + return *ParagraphComment->get("Children"); +} + +static json::Value extractVerbatimComments(json::Array VerbatimLines) { + json::Value TextArray = json::Array(); + auto &TextArrayRef = *TextArray.getAsArray(); + for (auto &Line : VerbatimLines) + TextArrayRef.push_back(*Line.getAsObject() + ->get("VerbatimBlockLineComment") + ->getAsObject() + ->get("Text")); + + return TextArray; +} + +static Object serializeComment(const CommentInfo &I, Object &Description) { // taken from PR #142273 Object Obj = Object(); @@ -70,7 +126,7 @@ static json::Value serializeComment(const CommentInfo &I) { auto &CARef = *ChildArr.getAsArray(); CARef.reserve(I.Children.size()); for (const auto &C : I.Children) - CARef.emplace_back(serializeComment(*C)); + CARef.emplace_back(serializeComment(*C, Description)); switch (I.Kind) { case CommentKind::CK_TextComment: { @@ -79,9 +135,11 @@ static json::Value serializeComment(const CommentInfo &I) { } case CommentKind::CK_BlockCommandComment: { - Child.insert({"Command", I.Name}); - Child.insert({"Children", ChildArr}); - Obj.insert({commentKindToString(I.Kind), ChildVal}); + auto TextCommentsArray = extractTextComments(CARef.front().getAsObject()); + if (I.Name == "brief") + insertComment(Description, TextCommentsArray, "BriefComments"); + else if (I.Name == "return") + insertComment(Description, TextCommentsArray, "ReturnComments"); return Obj; } @@ -103,17 +161,20 @@ static json::Value serializeComment(const CommentInfo &I) { Child.insert({"ParamName", I.ParamName}); Child.insert({"Direction", I.Direction}); Child.insert({"Explicit", I.Explicit}); - Child.insert({"Children", ChildArr}); - Obj.insert({commentKindToString(I.Kind), ChildVal}); + auto TextCommentsArray = extractTextComments(CARef.front().getAsObject()); + Child.insert({"Children", TextCommentsArray}); + if (I.Kind == CommentKind::CK_ParamCommandComment) + insertComment(Description, ChildVal, "ParamComments"); return Obj; } case CommentKind::CK_VerbatimBlockComment: { - Child.insert({"Text", I.Text}); - if (!I.CloseName.empty()) - Child.insert({"CloseName", I.CloseName}); - Child.insert({"Children", ChildArr}); - Obj.insert({commentKindToString(I.Kind), ChildVal}); + if (I.CloseName == "endcode") { + // We don't support \code language specification + auto TextCommentsArray = extractVerbatimComments(CARef); + insertComment(Description, TextCommentsArray, "CodeComments"); + } else if (I.CloseName == "endverbatim") + insertComment(Description, ChildVal, "VerbatimComments"); return Obj; } @@ -155,8 +216,8 @@ static json::Value serializeComment(const CommentInfo &I) { case CommentKind::CK_FullComment: case CommentKind::CK_ParagraphComment: { Child.insert({"Children", ChildArr}); - Obj.insert({commentKindToString(I.Kind), ChildVal}); - return Obj; + Child["ParagraphComment"] = true; + return Child; } case CommentKind::CK_Unknown: { @@ -172,6 +233,9 @@ serializeCommonAttributes(const Info &I, json::Object &Obj, const std::optional<StringRef> RepositoryUrl) { Obj["Name"] = I.Name; Obj["USR"] = toHex(toStringRef(I.USR)); + Obj["InfoType"] = infoTypeToString(I.IT); + if (!I.DocumentationFileName.empty()) + Obj["DocumentationFileName"] = I.DocumentationFileName; if (!I.Path.empty()) Obj["Path"] = I.Path; @@ -183,12 +247,20 @@ serializeCommonAttributes(const Info &I, json::Object &Obj, } if (!I.Description.empty()) { - json::Value DescArray = json::Array(); - auto &DescArrayRef = *DescArray.getAsArray(); - DescArrayRef.reserve(I.Description.size()); - for (const auto &Comment : I.Description) - DescArrayRef.push_back(serializeComment(Comment)); - Obj["Description"] = DescArray; + Object Description = Object(); + // Skip straight to the FullComment's children + auto &Comments = I.Description.at(0).Children; + for (const auto &CommentInfo : Comments) { + json::Value Comment = serializeComment(*CommentInfo, Description); + // if a ParagraphComment is returned, then it is a top-level comment that + // needs to be inserted manually. + if (auto *ParagraphComment = Comment.getAsObject(); + ParagraphComment->get("ParagraphComment")) { + auto TextCommentsArray = extractTextComments(ParagraphComment); + insertComment(Description, TextCommentsArray, "ParagraphComments"); + } + } + Obj["Description"] = std::move(Description); } // Namespaces aren't SymbolInfos, so they dont have a DefLoc @@ -205,6 +277,8 @@ static void serializeReference(const Reference &Ref, Object &ReferenceObj) { ReferenceObj["Name"] = Ref.Name; ReferenceObj["QualName"] = Ref.QualName; ReferenceObj["USR"] = toHex(toStringRef(Ref.USR)); + if (!Ref.DocumentationFileName.empty()) + ReferenceObj["DocumentationFileName"] = Ref.DocumentationFileName; } // Although namespaces and records both have ScopeChildren, they serialize them @@ -217,14 +291,18 @@ serializeCommonChildren(const ScopeChildren &Children, json::Object &Obj, serializeInfo(Info, Object, RepositoryUrl); }; - if (!Children.Enums.empty()) + if (!Children.Enums.empty()) { serializeArray(Children.Enums, Obj, "Enums", SerializeInfo); + Obj["HasEnums"] = true; + } if (!Children.Typedefs.empty()) serializeArray(Children.Typedefs, Obj, "Typedefs", SerializeInfo); - if (!Children.Records.empty()) + if (!Children.Records.empty()) { serializeArray(Children.Records, Obj, "Records", SerializeReferenceLambda); + Obj["HasRecords"] = true; + } } template <typename Container, typename SerializationFunc> @@ -234,10 +312,12 @@ static void serializeArray(const Container &Records, Object &Obj, json::Value RecordsArray = Array(); auto &RecordsArrayRef = *RecordsArray.getAsArray(); RecordsArrayRef.reserve(Records.size()); - for (const auto &Item : Records) { + for (size_t Index = 0; Index < Records.size(); ++Index) { json::Value ItemVal = Object(); auto &ItemObj = *ItemVal.getAsObject(); - SerializeInfo(Item, ItemObj); + SerializeInfo(Records[Index], ItemObj); + if (Index == Records.size() - 1) + ItemObj["End"] = true; RecordsArrayRef.push_back(ItemVal); } Obj[Key] = RecordsArray; @@ -380,6 +460,11 @@ static void serializeInfo(const FriendInfo &I, Object &Obj) { } } +static void insertArray(Object &Obj, json::Value &Array, StringRef Key) { + Obj[Key] = Array; + Obj["Has" + Key.str()] = true; +} + static void serializeInfo(const RecordInfo &I, json::Object &Obj, const std::optional<StringRef> &RepositoryUrl) { serializeCommonAttributes(I, Obj, RepositoryUrl); @@ -406,7 +491,7 @@ static void serializeInfo(const RecordInfo &I, json::Object &Obj, } if (!PubFunctionsArrayRef.empty()) - Obj["PublicFunctions"] = PubFunctionsArray; + insertArray(Obj, PubFunctionsArray, "PublicFunctions"); if (!ProtFunctionsArrayRef.empty()) Obj["ProtectedFunctions"] = ProtFunctionsArray; } @@ -430,7 +515,7 @@ static void serializeInfo(const RecordInfo &I, json::Object &Obj, } if (!PubMembersArrayRef.empty()) - Obj["PublicMembers"] = PublicMembersArray; + insertArray(Obj, PublicMembersArray, "PublicMembers"); if (!ProtMembersArrayRef.empty()) Obj["ProtectedMembers"] = ProtectedMembersArray; } @@ -496,10 +581,7 @@ static SmallString<16> determineFileName(Info *I, SmallString<128> &Path) { SmallString<16> FileName; if (I->IT == InfoType::IT_record) { auto *RecordSymbolInfo = static_cast<SymbolInfo *>(I); - if (RecordSymbolInfo->MangledName.size() < 255) - FileName = RecordSymbolInfo->MangledName; - else - FileName = toStringRef(toHex(RecordSymbolInfo->USR)); + FileName = RecordSymbolInfo->MangledName; } else if (I->IT == InfoType::IT_namespace && I->Name != "") // Serialize the global namespace as index.json FileName = I->Name; @@ -527,7 +609,10 @@ Error JSONGenerator::generateDocs( } SmallString<16> FileName = determineFileName(Info, Path); + if (FileToInfos.contains(Path)) + continue; FileToInfos[Path].push_back(Info); + Info->DocumentationFileName = FileName; } for (const auto &Group : FileToInfos) { diff --git a/clang-tools-extra/clang-doc/Representation.cpp b/clang-tools-extra/clang-doc/Representation.cpp index beaf314..929112f 100644 --- a/clang-tools-extra/clang-doc/Representation.cpp +++ b/clang-tools-extra/clang-doc/Representation.cpp @@ -247,6 +247,8 @@ void Reference::merge(Reference &&Other) { Name = Other.Name; if (Path.empty()) Path = Other.Path; + if (DocumentationFileName.empty()) + DocumentationFileName = Other.DocumentationFileName; } bool FriendInfo::mergeable(const FriendInfo &Other) { @@ -500,13 +502,13 @@ ClangDocContext::ClangDocContext(tooling::ExecutionContext *ECtx, } void ScopeChildren::sort() { - llvm::sort(Namespaces.begin(), Namespaces.end()); - llvm::sort(Records.begin(), Records.end()); - llvm::sort(Functions.begin(), Functions.end()); - llvm::sort(Enums.begin(), Enums.end()); - llvm::sort(Typedefs.begin(), Typedefs.end()); - llvm::sort(Concepts.begin(), Concepts.end()); - llvm::sort(Variables.begin(), Variables.end()); + llvm::sort(Namespaces); + llvm::sort(Records); + llvm::sort(Functions); + llvm::sort(Enums); + llvm::sort(Typedefs); + llvm::sort(Concepts); + llvm::sort(Variables); } } // namespace doc } // namespace clang diff --git a/clang-tools-extra/clang-doc/Representation.h b/clang-tools-extra/clang-doc/Representation.h index 23f0e90..2a75f89 100644 --- a/clang-tools-extra/clang-doc/Representation.h +++ b/clang-tools-extra/clang-doc/Representation.h @@ -121,6 +121,10 @@ struct Reference { Reference(SymbolID USR, StringRef Name, InfoType IT, StringRef QualName, StringRef Path = StringRef()) : USR(USR), Name(Name), QualName(QualName), RefType(IT), Path(Path) {} + Reference(SymbolID USR, StringRef Name, InfoType IT, StringRef QualName, + StringRef Path, SmallString<16> DocumentationFileName) + : USR(USR), Name(Name), QualName(QualName), RefType(IT), Path(Path), + DocumentationFileName(DocumentationFileName) {} bool operator==(const Reference &Other) const { return std::tie(USR, Name, QualName, RefType) == @@ -155,6 +159,7 @@ struct Reference { // Path of directory where the clang-doc generated file will be saved // (possibly unresolved) llvm::SmallString<128> Path; + SmallString<16> DocumentationFileName; }; // Holds the children of a record or namespace. @@ -331,6 +336,11 @@ struct Info { llvm::SmallString<128> Path; // Path of directory where the clang-doc // generated file will be saved + // The name used for the file that this info is documented in. + // In the JSON generator, infos are documented in files with mangled names. + // Thus, we keep track of the physical filename for linking purposes. + SmallString<16> DocumentationFileName; + void mergeBase(Info &&I); bool mergeable(const Info &Other); diff --git a/clang-tools-extra/clang-doc/Serialize.cpp b/clang-tools-extra/clang-doc/Serialize.cpp index 7a0e00c..de73f68 100644 --- a/clang-tools-extra/clang-doc/Serialize.cpp +++ b/clang-tools-extra/clang-doc/Serialize.cpp @@ -495,7 +495,8 @@ static void InsertChild(ScopeChildren &Scope, const NamespaceInfo &Info) { static void InsertChild(ScopeChildren &Scope, const RecordInfo &Info) { Scope.Records.emplace_back(Info.USR, Info.Name, InfoType::IT_record, - Info.Name, getInfoRelativePath(Info.Namespace)); + Info.Name, getInfoRelativePath(Info.Namespace), + Info.MangledName); } static void InsertChild(ScopeChildren &Scope, EnumInfo Info) { @@ -777,7 +778,13 @@ static void populateSymbolInfo(SymbolInfo &I, const T *D, const FullComment *C, Mangler->mangleCXXVTable(CXXD, MangledStream); else MangledStream << D->getNameAsString(); - I.MangledName = MangledName; + if (MangledName.size() > 255) + // File creation fails if the mangled name is too long, so default to the + // USR. We should look for a better check since filesystems differ in + // maximum filename length + I.MangledName = llvm::toStringRef(llvm::toHex(I.USR)); + else + I.MangledName = MangledName; delete Mangler; } diff --git a/clang-tools-extra/clang-doc/assets/clang-doc-mustache.css b/clang-tools-extra/clang-doc/assets/clang-doc-mustache.css index a885a36..e555ee7 100644 --- a/clang-tools-extra/clang-doc/assets/clang-doc-mustache.css +++ b/clang-tools-extra/clang-doc/assets/clang-doc-mustache.css @@ -469,3 +469,7 @@ a, a:visited, a:hover, a:active { text-decoration: none; color: inherit; } + +.code-block { + white-space: pre-line; +} diff --git a/clang-tools-extra/clang-doc/assets/class-template.mustache b/clang-tools-extra/clang-doc/assets/class-template.mustache index f9e78f5..b1a7470 100644 --- a/clang-tools-extra/clang-doc/assets/class-template.mustache +++ b/clang-tools-extra/clang-doc/assets/class-template.mustache @@ -44,20 +44,20 @@ <main> <div class="container"> <div class="sidebar"> - <h2>{{RecordType}} {{Name}}</h2> + <h2>{{TagType}} {{Name}}</h2> <ul> - {{#PublicMembers}} + {{#HasPublicMembers}} <li class="sidebar-section"> - <a class="sidebar-item" href="#PublicMethods">Public Members</a> + <a class="sidebar-item" href="#PublicMembers">Public Members</a> </li> <ul> - {{#Obj}} + {{#PublicMembers}} <li class="sidebar-item-container"> <a class="sidebar-item" href="#{{Name}}">{{Name}}</a> </li> - {{/Obj}} + {{/PublicMembers}} </ul> - {{/PublicMembers}} + {{/HasPublicMembers}} {{#ProtectedMembers}} <li class="sidebar-section"> <a class="sidebar-item" href="#PublicMethods">Protected Members</a> @@ -70,18 +70,18 @@ {{/Obj}} </ul> {{/ProtectedMembers}} - {{#PublicFunction}} + {{#HasPublicFunctions}} <li class="sidebar-section"> <a class="sidebar-item" href="#PublicMethods">Public Method</a> </li> <ul> - {{#Obj}} + {{#PublicFunctions}} <li class="sidebar-item-container"> - <a class="sidebar-item" href="#{{ID}}">{{Name}}</a> + <a class="sidebar-item" href="#{{USR}}">{{Name}}</a> </li> - {{/Obj}} + {{/PublicFunctions}} </ul> - {{/PublicFunction}} + {{/HasPublicFunctions}} {{#ProtectedFunction}} <li class="sidebar-section"> <a class="sidebar-item" href="#ProtectedFunction">Protected Method</a> @@ -101,7 +101,7 @@ <ul> {{#Obj}} <li class="sidebar-item-container"> - <a class="sidebar-item" href="#{{ID}}">{{EnumName}}</a> + <a class="sidebar-item" href="#{{USR}}">{{EnumName}}</a> </li> {{/Obj}} </ul> @@ -127,22 +127,22 @@ <div class="content"> <section class="hero section-container"> <div class="hero__title"> - <h1 class="hero__title-large">{{RecordType}} {{Name}}</h1> - {{#RecordComments}} + <h1 class="hero__title-large">{{TagType}} {{Name}}</h1> + {{#Description}} <div class="hero__subtitle"> {{>Comments}} </div> - {{/RecordComments}} + {{/Description}} </div> </section> - {{#PublicMembers}} + {{#HasPublicMembers}} <section id="PublicMembers" class="section-container"> <h2>Public Members</h2> <div> - {{#Obj}} + {{#PublicMembers}} <div id="{{Name}}" class="delimiter-container"> <pre> -<code class="language-cpp code-clang-doc" >{{Type}} {{Name}}</code> + <code class="language-cpp code-clang-doc" >{{Type}} {{Name}}</code> </pre> {{#MemberComments}} <div> @@ -150,10 +150,10 @@ </div> {{/MemberComments}} </div> - {{/Obj}} + {{/PublicMembers}} </div> </section> - {{/PublicMembers}} + {{/HasPublicMembers}} {{#ProtectedMembers}} <section id="ProtectedMembers" class="section-container"> <h2>Protected Members</h2> @@ -173,26 +173,28 @@ </div> </section> {{/ProtectedMembers}} - {{#PublicFunction}} + {{#HasPublicFunctions}} <section id="PublicMethods" class="section-container"> <h2>Public Methods</h2> <div> - {{#Obj}} + {{#PublicFunctions}} {{>FunctionPartial}} - {{/Obj}} + {{/PublicFunctions}} </div> </section> - {{/PublicFunction}} - {{#ProtectedFunction}} - <section id="ProtectedFunction" class="section-container"> - <h2>Protected Methods</h2> - <div> + {{/PublicFunctions}} + {{#ProtectedFunction}} + <li class="sidebar-section"> + <a class="sidebar-item" href="#ProtectedFunction">Protected Method</a> + </li> + <ul> {{#Obj}} -{{>FunctionPartial}} + <li class="sidebar-item-container"> + <a class="sidebar-item" href="#{{ID}}">{{Name}}</a> + </li> {{/Obj}} - </div> - </section> - {{/ProtectedFunction}} + </ul> + {{/ProtectedFunction}} {{#Enums}} <section id="Enums" class="section-container"> <h2>Enumerations</h2> diff --git a/clang-tools-extra/clang-doc/assets/comment-template.mustache b/clang-tools-extra/clang-doc/assets/comment-template.mustache index 723ace7..4e38e5f 100644 --- a/clang-tools-extra/clang-doc/assets/comment-template.mustache +++ b/clang-tools-extra/clang-doc/assets/comment-template.mustache @@ -5,16 +5,55 @@ This file defines templates for generating comments }} -{{#FullComment}} - {{#Children}} - {{>Comments}} - {{/Children}} -{{/FullComment}} +{{#BriefComments}} + <div> + {{#.}} + <p>{{TextComment}}</p> + {{/.}} + </div> +{{/BriefComments}} +{{#ParagraphComments}} + <div> + {{#.}} + <p>{{TextComment}}</p> + {{/.}} + </div> +{{/ParagraphComments}} {{#ParagraphComment}} {{#Children}} {{>Comments}} {{/Children}} {{/ParagraphComment}} +{{#HasParamComments}} + <h3>Parameters</h3> + {{#ParamComments}} + <div> + <b>{{ParamName}}</b> {{#Explicit}}{{Direction}}{{/Explicit}} {{#Children}}{{>Comments}}{{/Children}} + </div> + {{/ParamComments}} +{{/HasParamComments}} +{{#HasReturnComments}} + <h3>Returns</h3> + {{#ReturnComments}} + {{#.}} + <p>{{TextComment}}</p> + {{/.}} + {{/ReturnComments}} +{{/HasReturnComments}} +{{#HasCodeComments}} + <h3>Code</h3> + {{#CodeComments}} + <div> + <pre class="code-block"> + <code> + {{#.}} + {{.}} + {{/.}} + </code> + </pre> + </div> + {{/CodeComments}} +{{/HasCodeComments}} {{#BlockCommandComment}} <div class="block-command-comment__command"> <div class="block-command-command"> diff --git a/clang-tools-extra/clang-doc/assets/enum-template.mustache b/clang-tools-extra/clang-doc/assets/enum-template.mustache index c459884..53da466 100644 --- a/clang-tools-extra/clang-doc/assets/enum-template.mustache +++ b/clang-tools-extra/clang-doc/assets/enum-template.mustache @@ -9,7 +9,7 @@ <div> <pre> <code class="language-cpp code-clang-doc"> -{{EnumName}} +enum {{Name}} </code> </pre> </div> @@ -23,15 +23,21 @@ <th>Comment</th> {{/HasComment}} </tr> - {{#EnumValues}} + {{#Members}} <tr> <td>{{Name}}</td> + {{! A ValueExpr is an explicitly assigned enum value }} + {{#Value}} <td>{{Value}}</td> + {{/Value}} + {{^Value}} + <td>{{ValueExpr}}</td> + {{/Value}} {{#EnumValueComments}} <td>{{>Comments}}</td> {{/EnumValueComments}} </tr> - {{/EnumValues}} + {{/Members}} </tbody> </table> {{#EnumComments}} diff --git a/clang-tools-extra/clang-doc/assets/function-template.mustache b/clang-tools-extra/clang-doc/assets/function-template.mustache index 86e934a..2510a4d 100644 --- a/clang-tools-extra/clang-doc/assets/function-template.mustache +++ b/clang-tools-extra/clang-doc/assets/function-template.mustache @@ -6,7 +6,7 @@ This file defines the template for functions/methods }} <div class="delimiter-container"> - <div id="{{ID}}"> + <div id="{{USR}}"> {{! Function Prototype }} <pre> <code class="language-cpp code-clang-doc"> @@ -14,10 +14,10 @@ </code> </pre> {{! Function Comments }} - {{#FunctionComments}} + {{#Description}} <div> {{>Comments}} </div> - {{/FunctionComments}} + {{/Description}} </div> </div> diff --git a/clang-tools-extra/clang-doc/assets/namespace-template.mustache b/clang-tools-extra/clang-doc/assets/namespace-template.mustache index 1a44ed3..d96bc5c 100644 --- a/clang-tools-extra/clang-doc/assets/namespace-template.mustache +++ b/clang-tools-extra/clang-doc/assets/namespace-template.mustache @@ -46,56 +46,61 @@ <div class="sidebar"> <h2>{{RecordType}} {{Name}}</h2> <ul> - {{#Enums}} + {{#HasEnums}} <li class="sidebar-section"> <a class="sidebar-item" href="#Enums">Enums</a> </li> <ul> - {{#Obj}} + {{#Enums}} <li class="sidebar-item-container"> - <a class="sidebar-item" href="#{{ID}}">{{EnumName}}</a> + <a class="sidebar-item" href="#{{USR}}">{{Name}}</a> </li> - {{/Obj}} + {{/Enums}} </ul> - {{/Enums}} - {{#Record}} + {{/HasEnums}} + {{#HasRecords}} <li class="sidebar-section"> <a class="sidebar-item" href="#Classes">Inner Classes</a> </li> <ul> - {{#Links}} + {{#Records}} <li class="sidebar-item-container"> - <a class="sidebar-item" href="#{{ID}}">{{Name}}</a> + <a class="sidebar-item" href="#{{USR}}">{{Name}}</a> </li> - {{/Links}} + {{/Records}} </ul> - {{/Record}} + {{/HasRecrods}} </ul> </div> <div class="resizer" id="resizer"></div> <div class="content"> - {{#Enums}} + {{#HasEnums}} <section id="Enums" class="section-container"> <h2>Enumerations</h2> <div> - {{#Obj}} + {{#Enums}} {{>EnumPartial}} - {{/Obj}} + {{/Enums}} </div> </section> - {{/Enums}} - {{#Record}} + {{/HasEnums}} + + {{#HasRecords}} <section id="Classes" class="section-container"> <h2>Inner Classes</h2> <ul class="class-container"> - {{#Links}} - <li id="{{ID}}" style="max-height: 40px;"> - <a href="{{Link}}"><pre><code class="language-cpp code-clang-doc" >class {{Name}}</code></pre></a> + {{#Records}} + <li id="{{USR}}" style="max-height: 40px;"> + <a href="{{DocumentationFileName}}.html"> + <pre> + <code class="language-cpp code-clang-doc">class {{Name}}</code> + </pre> + </a> </li> - {{/Links}} + {{/Records}} </ul> + {{/HasRecords}} </section> - {{/Record}} </div> </div> </main> diff --git a/clang-tools-extra/clang-include-fixer/tool/ClangIncludeFixer.cpp b/clang-tools-extra/clang-include-fixer/tool/ClangIncludeFixer.cpp index 9f73f47..568cb2b 100644 --- a/clang-tools-extra/clang-include-fixer/tool/ClangIncludeFixer.cpp +++ b/clang-tools-extra/clang-include-fixer/tool/ClangIncludeFixer.cpp @@ -454,7 +454,7 @@ int includeFixerMain(int argc, const char **argv) { // Set up a new source manager for applying the resulting replacements. DiagnosticOptions DiagOpts; - DiagnosticsEngine Diagnostics(new DiagnosticIDs, DiagOpts); + DiagnosticsEngine Diagnostics(DiagnosticIDs::create(), DiagOpts); TextDiagnosticPrinter DiagnosticPrinter(outs(), DiagOpts); SourceManager SM(Diagnostics, tool.getFiles()); Diagnostics.setClient(&DiagnosticPrinter, false); diff --git a/clang-tools-extra/clang-move/tool/ClangMove.cpp b/clang-tools-extra/clang-move/tool/ClangMove.cpp index 750eb95..1be3cb1 100644 --- a/clang-tools-extra/clang-move/tool/ClangMove.cpp +++ b/clang-tools-extra/clang-move/tool/ClangMove.cpp @@ -178,9 +178,8 @@ int main(int argc, const char **argv) { DiagnosticOptions DiagOpts; clang::TextDiagnosticPrinter DiagnosticPrinter(errs(), DiagOpts); - DiagnosticsEngine Diagnostics( - IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), DiagOpts, - &DiagnosticPrinter, false); + DiagnosticsEngine Diagnostics(DiagnosticIDs::create(), DiagOpts, + &DiagnosticPrinter, false); auto &FileMgr = Tool.getFiles(); SourceManager SM(Diagnostics, FileMgr); Rewriter Rewrite(SM, LangOptions()); diff --git a/clang-tools-extra/clang-reorder-fields/tool/ClangReorderFields.cpp b/clang-tools-extra/clang-reorder-fields/tool/ClangReorderFields.cpp index 0350252..fbfce07 100644 --- a/clang-tools-extra/clang-reorder-fields/tool/ClangReorderFields.cpp +++ b/clang-tools-extra/clang-reorder-fields/tool/ClangReorderFields.cpp @@ -74,9 +74,8 @@ int main(int argc, const char **argv) { LangOptions DefaultLangOptions; DiagnosticOptions DiagOpts; TextDiagnosticPrinter DiagnosticPrinter(errs(), DiagOpts); - DiagnosticsEngine Diagnostics( - IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), DiagOpts, - &DiagnosticPrinter, false); + DiagnosticsEngine Diagnostics(DiagnosticIDs::create(), DiagOpts, + &DiagnosticPrinter, false); auto &FileMgr = Tool.getFiles(); SourceManager Sources(Diagnostics, FileMgr); diff --git a/clang-tools-extra/clang-tidy/.clang-tidy b/clang-tools-extra/clang-tidy/.clang-tidy index 2443c97..0a2ea24 100644 --- a/clang-tools-extra/clang-tidy/.clang-tidy +++ b/clang-tools-extra/clang-tidy/.clang-tidy @@ -22,7 +22,6 @@ Checks: > -performance-unnecessary-value-param, readability-*, -readability-avoid-nested-conditional-operator, - -readability-avoid-return-with-void-value, -readability-braces-around-statements, -readability-container-contains, -readability-convert-member-functions-to-static, diff --git a/clang-tools-extra/clang-tidy/ClangTidy.cpp b/clang-tools-extra/clang-tidy/ClangTidy.cpp index e84be04..4ae2864 100644 --- a/clang-tools-extra/clang-tidy/ClangTidy.cpp +++ b/clang-tools-extra/clang-tidy/ClangTidy.cpp @@ -96,8 +96,7 @@ public: llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS) : Files(FileSystemOptions(), std::move(BaseFS)), DiagPrinter(new TextDiagnosticPrinter(llvm::outs(), DiagOpts)), - Diags(IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), DiagOpts, - DiagPrinter), + Diags(DiagnosticIDs::create(), DiagOpts, DiagPrinter), SourceMgr(Diags, Files), Context(Context), ApplyFixes(ApplyFixes) { DiagOpts.ShowColors = Context.getOptions().UseColor.value_or( llvm::sys::Process::StandardOutHasColors()); @@ -570,7 +569,7 @@ runClangTidy(clang::tidy::ClangTidyContext &Context, ClangTidyDiagnosticConsumer DiagConsumer(Context, nullptr, true, ApplyAnyFix); auto DiagOpts = std::make_unique<DiagnosticOptions>(); - DiagnosticsEngine DE(new DiagnosticIDs(), *DiagOpts, &DiagConsumer, + DiagnosticsEngine DE(DiagnosticIDs::create(), *DiagOpts, &DiagConsumer, /*ShouldOwnClient=*/false); Context.setDiagnosticsEngine(std::move(DiagOpts), &DE); Tool.setDiagnosticConsumer(&DiagConsumer); diff --git a/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.cpp b/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.cpp index 2c17cd3..5e705f7 100644 --- a/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.cpp +++ b/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.cpp @@ -71,7 +71,7 @@ ExpandModularHeadersPPCallbacks::ExpandModularHeadersPPCallbacks( InMemoryFs(new llvm::vfs::InMemoryFileSystem), Sources(Compiler.getSourceManager()), // Forward the new diagnostics to the original DiagnosticConsumer. - Diags(new DiagnosticIDs, DiagOpts, + Diags(DiagnosticIDs::create(), DiagOpts, new ForwardingDiagnosticConsumer(Compiler.getDiagnosticClient())), LangOpts(Compiler.getLangOpts()), HSOpts(Compiler.getHeaderSearchOpts()) { // Add a FileSystem containing the extra files needed in place of modular diff --git a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp index ed1fd13..824ebdf 100644 --- a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp @@ -38,6 +38,7 @@ #include "IncorrectRoundingsCheck.h" #include "InfiniteLoopCheck.h" #include "IntegerDivisionCheck.h" +#include "InvalidEnumDefaultInitializationCheck.h" #include "LambdaFunctionNameCheck.h" #include "MacroParenthesesCheck.h" #include "MacroRepeatedSideEffectsCheck.h" @@ -165,6 +166,8 @@ public: CheckFactories.registerCheck<InfiniteLoopCheck>("bugprone-infinite-loop"); CheckFactories.registerCheck<IntegerDivisionCheck>( "bugprone-integer-division"); + CheckFactories.registerCheck<InvalidEnumDefaultInitializationCheck>( + "bugprone-invalid-enum-default-initialization"); CheckFactories.registerCheck<LambdaFunctionNameCheck>( "bugprone-lambda-function-name"); CheckFactories.registerCheck<MacroParenthesesCheck>( diff --git a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt index d862794..59928e5 100644 --- a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt @@ -30,6 +30,7 @@ add_clang_library(clangTidyBugproneModule STATIC InaccurateEraseCheck.cpp IncorrectEnableIfCheck.cpp IncorrectEnableSharedFromThisCheck.cpp + InvalidEnumDefaultInitializationCheck.cpp UnintendedCharOstreamOutputCheck.cpp ReturnConstRefFromParameterCheck.cpp SuspiciousStringviewDataUsageCheck.cpp diff --git a/clang-tools-extra/clang-tidy/bugprone/InvalidEnumDefaultInitializationCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/InvalidEnumDefaultInitializationCheck.cpp new file mode 100644 index 0000000..33fcf45 --- /dev/null +++ b/clang-tools-extra/clang-tidy/bugprone/InvalidEnumDefaultInitializationCheck.cpp @@ -0,0 +1,180 @@ +//===--- InvalidEnumDefaultInitializationCheck.cpp - clang-tidy -----------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "InvalidEnumDefaultInitializationCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/TypeVisitor.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include <algorithm> + +using namespace clang::ast_matchers; + +namespace clang::tidy::bugprone { + +namespace { + +bool isCompleteAndHasNoZeroValue(const EnumDecl *D) { + const EnumDecl *Definition = D->getDefinition(); + return Definition && Definition->isComplete() && + !Definition->enumerators().empty() && + std::none_of(Definition->enumerator_begin(), + Definition->enumerator_end(), + [](const EnumConstantDecl *Value) { + return Value->getInitVal().isZero(); + }); +} + +AST_MATCHER(EnumDecl, isCompleteAndHasNoZeroValue) { + return isCompleteAndHasNoZeroValue(&Node); +} + +// Find an initialization which initializes the value (if it has enum type) to a +// default zero value. +AST_MATCHER(Expr, isEmptyInit) { + if (isa<CXXScalarValueInitExpr, ImplicitValueInitExpr>(&Node)) + return true; + if (const auto *Init = dyn_cast<InitListExpr>(&Node)) { + if (Init->getNumInits() == 0) + return true; + } + return false; +} + +AST_MATCHER(InitListExpr, hasArrayFiller) { return Node.hasArrayFiller(); } + +// Check if any type has a "child" type that is an enum without zero value. +// The "child" type can be an array element type or member type of a record +// type (or a recursive combination of these). In this case, if the "root" type +// is statically initialized, the enum component is initialized to zero. +class FindEnumMember : public TypeVisitor<FindEnumMember, bool> { +public: + const EnumType *FoundEnum = nullptr; + + bool VisitType(const Type *T) { + const Type *DesT = T->getUnqualifiedDesugaredType(); + if (DesT != T) + return Visit(DesT); + return false; + } + bool VisitArrayType(const ArrayType *T) { + return Visit(T->getElementType().getTypePtr()); + } + bool VisitConstantArrayType(const ConstantArrayType *T) { + return Visit(T->getElementType().getTypePtr()); + } + bool VisitEnumType(const EnumType *T) { + if (isCompleteAndHasNoZeroValue(T->getDecl())) { + FoundEnum = T; + return true; + } + return false; + } + bool VisitRecordType(const RecordType *T) { + const RecordDecl *RD = T->getDecl(); + if (RD->isUnion()) + return false; + auto VisitField = [this](const FieldDecl *F) { + return Visit(F->getType().getTypePtr()); + }; + return llvm::any_of(RD->fields(), VisitField); + } +}; + +} // namespace + +InvalidEnumDefaultInitializationCheck::InvalidEnumDefaultInitializationCheck( + StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + +void InvalidEnumDefaultInitializationCheck::registerMatchers( + MatchFinder *Finder) { + auto EnumWithoutZeroValue = enumType( + hasDeclaration(enumDecl(isCompleteAndHasNoZeroValue()).bind("enum"))); + auto EnumOrArrayOfEnum = qualType(hasUnqualifiedDesugaredType( + anyOf(EnumWithoutZeroValue, + arrayType(hasElementType(qualType( + hasUnqualifiedDesugaredType(EnumWithoutZeroValue))))))); + Finder->addMatcher( + expr(isEmptyInit(), hasType(EnumOrArrayOfEnum)).bind("expr"), this); + + // Array initialization can contain an "array filler" for the (syntactically) + // unspecified elements. This expression is not found by AST matchers and can + // have any type (the array's element type). This is an implicitly generated + // initialization, so if the type contains somewhere an enum without zero + // enumerator, the zero initialization applies here. We search this array + // element type for the specific enum type manually when this matcher matches. + Finder->addMatcher(initListExpr(hasArrayFiller()).bind("array_filler_expr"), + this); +} + +void InvalidEnumDefaultInitializationCheck::check( + const MatchFinder::MatchResult &Result) { + const auto *InitExpr = Result.Nodes.getNodeAs<Expr>("expr"); + const auto *Enum = Result.Nodes.getNodeAs<EnumDecl>("enum"); + if (!InitExpr) { + const auto *InitList = + Result.Nodes.getNodeAs<InitListExpr>("array_filler_expr"); + // Initialization of omitted array elements with array filler was found. + // Check the type for enum without zero value. + // FIXME: In this way only one enum-typed value is found, not all of these. + FindEnumMember Finder; + if (!Finder.Visit(InitList->getArrayFiller()->getType().getTypePtr())) + return; + InitExpr = InitList; + Enum = Finder.FoundEnum->getDecl(); + } + + if (!InitExpr || !Enum) + return; + + ASTContext &ACtx = Enum->getASTContext(); + SourceLocation Loc = InitExpr->getExprLoc(); + if (Loc.isInvalid()) { + if (isa<ImplicitValueInitExpr, InitListExpr>(InitExpr)) { + DynTypedNodeList Parents = ACtx.getParents(*InitExpr); + if (Parents.empty()) + return; + + if (const auto *Ctor = Parents[0].get<CXXConstructorDecl>()) { + // Try to find member initializer with the found expression and get the + // source location from it. + CXXCtorInitializer *const *CtorInit = std::find_if( + Ctor->init_begin(), Ctor->init_end(), + [InitExpr](const CXXCtorInitializer *Init) { + return Init->isMemberInitializer() && Init->getInit() == InitExpr; + }); + if (!CtorInit) + return; + Loc = (*CtorInit)->getLParenLoc(); + } else if (const auto *InitList = Parents[0].get<InitListExpr>()) { + // The expression may be implicitly generated for an initialization. + // Search for a parent initialization list with valid source location. + while (InitList->getExprLoc().isInvalid()) { + DynTypedNodeList Parents = ACtx.getParents(*InitList); + if (Parents.empty()) + return; + InitList = Parents[0].get<InitListExpr>(); + if (!InitList) + return; + } + Loc = InitList->getExprLoc(); + } + } + // If still not found a source location, omit the warning. + // Ideally all such cases (if they exist) should be handled to make the + // check more precise. + if (Loc.isInvalid()) + return; + } + diag(Loc, "enum value of type %0 initialized with invalid value of 0, " + "enum doesn't have a zero-value enumerator") + << Enum; + diag(Enum->getLocation(), "enum is defined here", DiagnosticIDs::Note); +} + +} // namespace clang::tidy::bugprone diff --git a/clang-tools-extra/clang-tidy/bugprone/InvalidEnumDefaultInitializationCheck.h b/clang-tools-extra/clang-tidy/bugprone/InvalidEnumDefaultInitializationCheck.h new file mode 100644 index 0000000..0746c4d --- /dev/null +++ b/clang-tools-extra/clang-tidy/bugprone/InvalidEnumDefaultInitializationCheck.h @@ -0,0 +1,31 @@ +//===--- InvalidEnumDefaultInitializationCheck.h - clang-tidy -*- C++ -*---===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_INVALIDENUMDEFAULTINITIALIZATIONCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_INVALIDENUMDEFAULTINITIALIZATIONCHECK_H + +#include "../ClangTidyCheck.h" + +namespace clang::tidy::bugprone { + +/// Detects default initialization (to 0) of variables with `enum` type where +/// the enum has no enumerator with value of 0. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone/invalid-enum-default-initialization.html +class InvalidEnumDefaultInitializationCheck : public ClangTidyCheck { +public: + InvalidEnumDefaultInitializationCheck(StringRef Name, + ClangTidyContext *Context); + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +}; + +} // namespace clang::tidy::bugprone + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_INVALIDENUMDEFAULTINITIALIZATIONCHECK_H diff --git a/clang-tools-extra/clang-tidy/bugprone/NarrowingConversionsCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/NarrowingConversionsCheck.cpp index 8b2ca69..5378223 100644 --- a/clang-tools-extra/clang-tidy/bugprone/NarrowingConversionsCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/NarrowingConversionsCheck.cpp @@ -381,10 +381,11 @@ void NarrowingConversionsCheck::diagNarrowTypeOrConstant( const Expr &Rhs) { APValue Constant = getConstantExprValue(Context, Rhs); if (Constant.isInt()) - return diagNarrowIntegerConstant(SourceLoc, Lhs, Rhs, Constant.getInt()); - if (Constant.isFloat()) - return diagNarrowConstant(SourceLoc, Lhs, Rhs); - return diagNarrowType(SourceLoc, Lhs, Rhs); + diagNarrowIntegerConstant(SourceLoc, Lhs, Rhs, Constant.getInt()); + else if (Constant.isFloat()) + diagNarrowConstant(SourceLoc, Lhs, Rhs); + else + diagNarrowType(SourceLoc, Lhs, Rhs); } void NarrowingConversionsCheck::handleIntegralCast(const ASTContext &Context, @@ -460,10 +461,10 @@ void NarrowingConversionsCheck::handleFloatingToIntegral( llvm::APFloat FloatConstant(0.0); if (getFloatingConstantExprValue(Context, Rhs, FloatConstant)) { if (!isFloatExactlyRepresentable(Context, FloatConstant, Lhs.getType())) - return diagNarrowConstant(SourceLoc, Lhs, Rhs); + diagNarrowConstant(SourceLoc, Lhs, Rhs); - if (PedanticMode) - return diagConstantCast(SourceLoc, Lhs, Rhs); + else if (PedanticMode) + diagConstantCast(SourceLoc, Lhs, Rhs); return; } @@ -478,7 +479,7 @@ void NarrowingConversionsCheck::handleFloatingToIntegral( void NarrowingConversionsCheck::handleFloatingToBoolean( const ASTContext &Context, SourceLocation SourceLoc, const Expr &Lhs, const Expr &Rhs) { - return diagNarrowTypeOrConstant(Context, SourceLoc, Lhs, Rhs); + diagNarrowTypeOrConstant(Context, SourceLoc, Lhs, Rhs); } void NarrowingConversionsCheck::handleBooleanToSignedIntegral( @@ -532,19 +533,20 @@ void NarrowingConversionsCheck::handleBinaryOperator(const ASTContext &Context, if (LhsType == RhsType) return; if (RhsType->getKind() == BuiltinType::Bool && LhsType->isSignedInteger()) - return handleBooleanToSignedIntegral(Context, SourceLoc, Lhs, Rhs); - if (RhsType->isInteger() && LhsType->getKind() == BuiltinType::Bool) - return handleIntegralToBoolean(Context, SourceLoc, Lhs, Rhs); - if (RhsType->isInteger() && LhsType->isFloatingPoint()) - return handleIntegralToFloating(Context, SourceLoc, Lhs, Rhs); - if (RhsType->isInteger() && LhsType->isInteger()) - return handleIntegralCast(Context, SourceLoc, Lhs, Rhs); - if (RhsType->isFloatingPoint() && LhsType->getKind() == BuiltinType::Bool) - return handleFloatingToBoolean(Context, SourceLoc, Lhs, Rhs); - if (RhsType->isFloatingPoint() && LhsType->isInteger()) - return handleFloatingToIntegral(Context, SourceLoc, Lhs, Rhs); - if (RhsType->isFloatingPoint() && LhsType->isFloatingPoint()) - return handleFloatingCast(Context, SourceLoc, Lhs, Rhs); + handleBooleanToSignedIntegral(Context, SourceLoc, Lhs, Rhs); + else if (RhsType->isInteger() && LhsType->getKind() == BuiltinType::Bool) + handleIntegralToBoolean(Context, SourceLoc, Lhs, Rhs); + else if (RhsType->isInteger() && LhsType->isFloatingPoint()) + handleIntegralToFloating(Context, SourceLoc, Lhs, Rhs); + else if (RhsType->isInteger() && LhsType->isInteger()) + handleIntegralCast(Context, SourceLoc, Lhs, Rhs); + else if (RhsType->isFloatingPoint() && + LhsType->getKind() == BuiltinType::Bool) + handleFloatingToBoolean(Context, SourceLoc, Lhs, Rhs); + else if (RhsType->isFloatingPoint() && LhsType->isInteger()) + handleFloatingToIntegral(Context, SourceLoc, Lhs, Rhs); + else if (RhsType->isFloatingPoint() && LhsType->isFloatingPoint()) + handleFloatingCast(Context, SourceLoc, Lhs, Rhs); } bool NarrowingConversionsCheck::handleConditionalOperator( @@ -577,21 +579,28 @@ void NarrowingConversionsCheck::handleImplicitCast( SourceLocation SourceLoc = Lhs.getExprLoc(); switch (Cast.getCastKind()) { case CK_BooleanToSignedIntegral: - return handleBooleanToSignedIntegral(Context, SourceLoc, Lhs, Rhs); + handleBooleanToSignedIntegral(Context, SourceLoc, Lhs, Rhs); + return; case CK_IntegralToBoolean: - return handleIntegralToBoolean(Context, SourceLoc, Lhs, Rhs); + handleIntegralToBoolean(Context, SourceLoc, Lhs, Rhs); + return; case CK_IntegralToFloating: - return handleIntegralToFloating(Context, SourceLoc, Lhs, Rhs); + handleIntegralToFloating(Context, SourceLoc, Lhs, Rhs); + return; case CK_IntegralCast: - return handleIntegralCast(Context, SourceLoc, Lhs, Rhs); + handleIntegralCast(Context, SourceLoc, Lhs, Rhs); + return; case CK_FloatingToBoolean: - return handleFloatingToBoolean(Context, SourceLoc, Lhs, Rhs); + handleFloatingToBoolean(Context, SourceLoc, Lhs, Rhs); + return; case CK_FloatingToIntegral: - return handleFloatingToIntegral(Context, SourceLoc, Lhs, Rhs); + handleFloatingToIntegral(Context, SourceLoc, Lhs, Rhs); + return; case CK_FloatingCast: - return handleFloatingCast(Context, SourceLoc, Lhs, Rhs); + handleFloatingCast(Context, SourceLoc, Lhs, Rhs); + return; default: - break; + return; } } @@ -610,9 +619,10 @@ void NarrowingConversionsCheck::handleBinaryOperator(const ASTContext &Context, void NarrowingConversionsCheck::check(const MatchFinder::MatchResult &Result) { if (const auto *Op = Result.Nodes.getNodeAs<BinaryOperator>("binary_op")) - return handleBinaryOperator(*Result.Context, *Op); - if (const auto *Cast = Result.Nodes.getNodeAs<ImplicitCastExpr>("cast")) - return handleImplicitCast(*Result.Context, *Cast); - llvm_unreachable("must be binary operator or cast expression"); + handleBinaryOperator(*Result.Context, *Op); + else if (const auto *Cast = Result.Nodes.getNodeAs<ImplicitCastExpr>("cast")) + handleImplicitCast(*Result.Context, *Cast); + else + llvm_unreachable("must be binary operator or cast expression"); } } // namespace clang::tidy::bugprone diff --git a/clang-tools-extra/clang-tidy/bugprone/SignedCharMisuseCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/SignedCharMisuseCheck.cpp index ea3b8b8..dfd3cbf 100644 --- a/clang-tools-extra/clang-tidy/bugprone/SignedCharMisuseCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/SignedCharMisuseCheck.cpp @@ -74,17 +74,25 @@ void SignedCharMisuseCheck::registerMatchers(MatchFinder *Finder) { charCastExpression(true, IntegerType, "signedCastExpression"); const auto UnSignedCharCastExpr = charCastExpression(false, IntegerType, "unsignedCastExpression"); + const bool IsC23 = getLangOpts().C23; - // Catch assignments with signed char -> integer conversion. + // Catch assignments with signed char -> integer conversion. Ignore false + // positives on C23 enums with the fixed underlying type of signed char. const auto AssignmentOperatorExpr = expr(binaryOperator(hasOperatorName("="), hasLHS(hasType(IntegerType)), - hasRHS(SignedCharCastExpr))); + hasRHS(SignedCharCastExpr)), + IsC23 ? unless(binaryOperator( + hasLHS(hasType(hasCanonicalType(enumType()))))) + : Matcher<Stmt>(anything())); Finder->addMatcher(AssignmentOperatorExpr, this); - // Catch declarations with signed char -> integer conversion. - const auto Declaration = varDecl(isDefinition(), hasType(IntegerType), - hasInitializer(SignedCharCastExpr)); + // Catch declarations with signed char -> integer conversion. Ignore false + // positives on C23 enums with the fixed underlying type of signed char. + const auto Declaration = varDecl( + isDefinition(), hasType(IntegerType), hasInitializer(SignedCharCastExpr), + IsC23 ? unless(hasType(hasCanonicalType(enumType()))) + : Matcher<VarDecl>(anything())); Finder->addMatcher(Declaration, this); diff --git a/clang-tools-extra/clang-tidy/bugprone/UnhandledSelfAssignmentCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/UnhandledSelfAssignmentCheck.cpp index 1f432c4..c4c4267 100644 --- a/clang-tools-extra/clang-tidy/bugprone/UnhandledSelfAssignmentCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/UnhandledSelfAssignmentCheck.cpp @@ -69,6 +69,28 @@ void UnhandledSelfAssignmentCheck::registerMatchers(MatchFinder *Finder) { cxxMethodDecl(unless(hasDescendant(cxxMemberCallExpr(callee(cxxMethodDecl( hasName("operator="), ofClass(equalsBoundNode("class")))))))); + // Checking that some kind of constructor is called and followed by a `swap`: + // T& operator=(const T& other) { + // T tmp{this->internal_data(), some, other, args}; + // swap(tmp); + // return *this; + // } + const auto HasCopyAndSwap = cxxMethodDecl( + ofClass(cxxRecordDecl()), + hasBody(compoundStmt( + hasDescendant( + varDecl(hasType(cxxRecordDecl(equalsBoundNode("class")))) + .bind("tmp_var")), + hasDescendant(stmt(anyOf( + cxxMemberCallExpr(hasArgument( + 0, declRefExpr(to(varDecl(equalsBoundNode("tmp_var")))))), + callExpr( + callee(functionDecl(hasName("swap"))), argumentCountIs(2), + hasAnyArgument( + declRefExpr(to(varDecl(equalsBoundNode("tmp_var"))))), + hasAnyArgument(unaryOperator(has(cxxThisExpr()), + hasOperatorName("*")))))))))); + DeclarationMatcher AdditionalMatcher = cxxMethodDecl(); if (WarnOnlyIfThisHasSuspiciousField) { // Matcher for standard smart pointers. @@ -89,14 +111,14 @@ void UnhandledSelfAssignmentCheck::registerMatchers(MatchFinder *Finder) { hasType(arrayType()))))))); } - Finder->addMatcher(cxxMethodDecl(ofClass(cxxRecordDecl().bind("class")), - isCopyAssignmentOperator(), IsUserDefined, - HasReferenceParam, HasNoSelfCheck, - unless(HasNonTemplateSelfCopy), - unless(HasTemplateSelfCopy), - HasNoNestedSelfAssign, AdditionalMatcher) - .bind("copyAssignmentOperator"), - this); + Finder->addMatcher( + cxxMethodDecl( + ofClass(cxxRecordDecl().bind("class")), isCopyAssignmentOperator(), + IsUserDefined, HasReferenceParam, HasNoSelfCheck, + unless(HasNonTemplateSelfCopy), unless(HasTemplateSelfCopy), + unless(HasCopyAndSwap), HasNoNestedSelfAssign, AdditionalMatcher) + .bind("copyAssignmentOperator"), + this); } void UnhandledSelfAssignmentCheck::check( diff --git a/clang-tools-extra/clang-tidy/llvm/CMakeLists.txt b/clang-tools-extra/clang-tidy/llvm/CMakeLists.txt index 3232f6e..41386cd 100644 --- a/clang-tools-extra/clang-tidy/llvm/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/llvm/CMakeLists.txt @@ -11,6 +11,7 @@ add_clang_library(clangTidyLLVMModule STATIC PreferRegisterOverUnsignedCheck.cpp PreferStaticOverAnonymousNamespaceCheck.cpp TwineLocalCheck.cpp + UseNewMLIROpBuilderCheck.cpp LINK_LIBS clangTidy @@ -29,4 +30,5 @@ clang_target_link_libraries(clangTidyLLVMModule clangBasic clangLex clangTooling + clangTransformer ) diff --git a/clang-tools-extra/clang-tidy/llvm/LLVMTidyModule.cpp b/clang-tools-extra/clang-tidy/llvm/LLVMTidyModule.cpp index 0754530..c7c61fd 100644 --- a/clang-tools-extra/clang-tidy/llvm/LLVMTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/llvm/LLVMTidyModule.cpp @@ -18,6 +18,7 @@ #include "PreferRegisterOverUnsignedCheck.h" #include "PreferStaticOverAnonymousNamespaceCheck.h" #include "TwineLocalCheck.h" +#include "UseNewMLIROpBuilderCheck.h" namespace clang::tidy { namespace llvm_check { @@ -40,6 +41,8 @@ public: CheckFactories.registerCheck<readability::QualifiedAutoCheck>( "llvm-qualified-auto"); CheckFactories.registerCheck<TwineLocalCheck>("llvm-twine-local"); + CheckFactories.registerCheck<UseNewMlirOpBuilderCheck>( + "llvm-use-new-mlir-op-builder"); } ClangTidyOptions getModuleOptions() override { diff --git a/clang-tools-extra/clang-tidy/llvm/UseNewMLIROpBuilderCheck.cpp b/clang-tools-extra/clang-tidy/llvm/UseNewMLIROpBuilderCheck.cpp new file mode 100644 index 0000000..4722199 --- /dev/null +++ b/clang-tools-extra/clang-tidy/llvm/UseNewMLIROpBuilderCheck.cpp @@ -0,0 +1,139 @@ +//===--- UseNewMLIROpBuilderCheck.cpp - clang-tidy ------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "UseNewMLIROpBuilderCheck.h" +#include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/Basic/LLVM.h" +#include "clang/Lex/Lexer.h" +#include "clang/Tooling/Transformer/RangeSelector.h" +#include "clang/Tooling/Transformer/RewriteRule.h" +#include "clang/Tooling/Transformer/SourceCode.h" +#include "clang/Tooling/Transformer/Stencil.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/FormatVariadic.h" + +namespace clang::tidy::llvm_check { +namespace { + +using namespace ::clang::ast_matchers; +using namespace ::clang::transformer; + +EditGenerator rewrite(RangeSelector Call, RangeSelector Builder, + RangeSelector CallArgs) { + // This is using an EditGenerator rather than ASTEdit as we want to warn even + // if in macro. + return [Call = std::move(Call), Builder = std::move(Builder), + CallArgs = + std::move(CallArgs)](const MatchFinder::MatchResult &Result) + -> Expected<SmallVector<transformer::Edit, 1>> { + Expected<CharSourceRange> CallRange = Call(Result); + if (!CallRange) + return CallRange.takeError(); + SourceManager &SM = *Result.SourceManager; + const LangOptions &LangOpts = Result.Context->getLangOpts(); + SourceLocation Begin = CallRange->getBegin(); + + // This will result in just a warning and no edit. + bool InMacro = CallRange->getBegin().isMacroID(); + if (InMacro) { + while (SM.isMacroArgExpansion(Begin)) + Begin = SM.getImmediateExpansionRange(Begin).getBegin(); + Edit WarnOnly; + WarnOnly.Kind = EditKind::Range; + WarnOnly.Range = CharSourceRange::getCharRange(Begin, Begin); + return SmallVector<Edit, 1>({WarnOnly}); + } + + // This will try to extract the template argument as written so that the + // rewritten code looks closest to original. + auto NextToken = [&](std::optional<Token> CurrentToken) { + if (!CurrentToken) + return CurrentToken; + if (CurrentToken->getEndLoc() >= CallRange->getEnd()) + return std::optional<Token>(); + return clang::Lexer::findNextToken(CurrentToken->getLocation(), SM, + LangOpts); + }; + std::optional<Token> LessToken = + clang::Lexer::findNextToken(Begin, SM, LangOpts); + while (LessToken && LessToken->getKind() != clang::tok::less) { + LessToken = NextToken(LessToken); + } + if (!LessToken) { + return llvm::make_error<llvm::StringError>(llvm::errc::invalid_argument, + "missing '<' token"); + } + std::optional<Token> EndToken = NextToken(LessToken); + for (std::optional<Token> GreaterToken = NextToken(EndToken); + GreaterToken && GreaterToken->getKind() != clang::tok::greater; + GreaterToken = NextToken(GreaterToken)) { + EndToken = GreaterToken; + } + if (!EndToken) { + return llvm::make_error<llvm::StringError>(llvm::errc::invalid_argument, + "missing '>' token"); + } + + Expected<CharSourceRange> BuilderRange = Builder(Result); + if (!BuilderRange) + return BuilderRange.takeError(); + Expected<CharSourceRange> CallArgsRange = CallArgs(Result); + if (!CallArgsRange) + return CallArgsRange.takeError(); + + // Helper for concatting below. + auto GetText = [&](const CharSourceRange &Range) { + return clang::Lexer::getSourceText(Range, SM, LangOpts); + }; + + Edit Replace; + Replace.Kind = EditKind::Range; + Replace.Range = *CallRange; + std::string CallArgsStr; + // Only emit args if there are any. + if (auto CallArgsText = GetText(*CallArgsRange).ltrim(); + !CallArgsText.rtrim().empty()) { + CallArgsStr = llvm::formatv(", {}", CallArgsText); + } + Replace.Replacement = + llvm::formatv("{}::create({}{})", + GetText(CharSourceRange::getTokenRange( + LessToken->getEndLoc(), EndToken->getLastLoc())), + GetText(*BuilderRange), CallArgsStr); + + return SmallVector<Edit, 1>({Replace}); + }; +} + +RewriteRuleWith<std::string> useNewMlirOpBuilderCheckRule() { + Stencil message = cat("use 'OpType::create(builder, ...)' instead of " + "'builder.create<OpType>(...)'"); + // Match a create call on an OpBuilder. + ast_matchers::internal::Matcher<Stmt> base = + cxxMemberCallExpr( + on(expr(hasType( + cxxRecordDecl(isSameOrDerivedFrom("::mlir::OpBuilder")))) + .bind("builder")), + callee(cxxMethodDecl(hasTemplateArgument(0, templateArgument()))), + callee(cxxMethodDecl(hasName("create")))) + .bind("call"); + return applyFirst( + // Attempt rewrite given an lvalue builder, else just warn. + {makeRule(cxxMemberCallExpr(unless(on(cxxTemporaryObjectExpr())), base), + rewrite(node("call"), node("builder"), callArgs("call")), + message), + makeRule(base, noopEdit(node("call")), message)}); +} +} // namespace + +UseNewMlirOpBuilderCheck::UseNewMlirOpBuilderCheck(StringRef Name, + ClangTidyContext *Context) + : TransformerClangTidyCheck(useNewMlirOpBuilderCheckRule(), Name, Context) { +} + +} // namespace clang::tidy::llvm_check diff --git a/clang-tools-extra/clang-tidy/llvm/UseNewMLIROpBuilderCheck.h b/clang-tools-extra/clang-tidy/llvm/UseNewMLIROpBuilderCheck.h new file mode 100644 index 0000000..813a23c --- /dev/null +++ b/clang-tools-extra/clang-tidy/llvm/UseNewMLIROpBuilderCheck.h @@ -0,0 +1,29 @@ +//===--- UseNewMLIROpBuilderCheck.h - clang-tidy ----------------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_LLVM_USENEWMLIROPBUILDERCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_LLVM_USENEWMLIROPBUILDERCHECK_H + +#include "../utils/TransformerClangTidyCheck.h" + +namespace clang::tidy::llvm_check { + +/// Checks for uses of MLIR's old/to be deprecated `OpBuilder::create<T>` form +/// and suggests using `T::create` instead. +class UseNewMlirOpBuilderCheck : public utils::TransformerClangTidyCheck { +public: + UseNewMlirOpBuilderCheck(StringRef Name, ClangTidyContext *Context); + + bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { + return getLangOpts().CPlusPlus; + } +}; + +} // namespace clang::tidy::llvm_check + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_LLVM_USENEWMLIROPBUILDERCHECK_H diff --git a/clang-tools-extra/clang-tidy/misc/HeaderIncludeCycleCheck.cpp b/clang-tools-extra/clang-tidy/misc/HeaderIncludeCycleCheck.cpp index 21d443a..1f6ceda 100644 --- a/clang-tools-extra/clang-tidy/misc/HeaderIncludeCycleCheck.cpp +++ b/clang-tools-extra/clang-tidy/misc/HeaderIncludeCycleCheck.cpp @@ -13,8 +13,8 @@ #include "clang/Lex/Preprocessor.h" #include "llvm/Support/Regex.h" #include <algorithm> -#include <deque> #include <optional> +#include <vector> using namespace clang::ast_matchers; @@ -23,8 +23,8 @@ namespace clang::tidy::misc { namespace { struct Include { - FileID Id; - llvm::StringRef Name; + const FileEntry *File; + StringRef Name; SourceLocation Loc; }; @@ -50,31 +50,27 @@ public: if (Reason != EnterFile && Reason != ExitFile) return; - FileID Id = SM.getFileID(Loc); + const FileID Id = SM.getFileID(Loc); if (Id.isInvalid()) return; + const FileEntry *NewFile = SM.getFileEntryForID(Id); + const FileEntry *PrevFile = SM.getFileEntryForID(PrevFID); + if (Reason == ExitFile) { - if ((Files.size() > 1U) && (Files.back().Id == PrevFID) && - (Files[Files.size() - 2U].Id == Id)) + if ((Files.size() > 1U) && (Files.back().File == PrevFile) && + (Files[Files.size() - 2U].File == NewFile)) Files.pop_back(); return; } - if (!Files.empty() && Files.back().Id == Id) + if (!Files.empty() && Files.back().File == NewFile) return; - std::optional<llvm::StringRef> FilePath = SM.getNonBuiltinFilenameForID(Id); - llvm::StringRef FileName = - FilePath ? llvm::sys::path::filename(*FilePath) : llvm::StringRef(); - - if (!NextToEnter) - NextToEnter = Include{Id, FileName, SourceLocation()}; - - assert(NextToEnter->Name == FileName); - NextToEnter->Id = Id; - Files.emplace_back(*NextToEnter); - NextToEnter.reset(); + const std::optional<StringRef> FilePath = SM.getNonBuiltinFilenameForID(Id); + const StringRef FileName = + FilePath ? llvm::sys::path::filename(*FilePath) : StringRef(); + Files.push_back({NewFile, FileName, std::exchange(NextToEnter, {})}); } void InclusionDirective(SourceLocation, const Token &, StringRef FilePath, @@ -85,36 +81,26 @@ public: if (FileType != clang::SrcMgr::C_User) return; - llvm::StringRef FileName = llvm::sys::path::filename(FilePath); - NextToEnter = {FileID(), FileName, Range.getBegin()}; + NextToEnter = Range.getBegin(); if (!File) return; - FileID Id = SM.translateFile(*File); - if (Id.isInvalid()) - return; - - checkForDoubleInclude(Id, FileName, Range.getBegin()); - } - - void EndOfMainFile() override { - if (!Files.empty() && Files.back().Id == SM.getMainFileID()) - Files.pop_back(); - - assert(Files.empty()); + checkForDoubleInclude(&File->getFileEntry(), + llvm::sys::path::filename(FilePath), + Range.getBegin()); } - void checkForDoubleInclude(FileID Id, llvm::StringRef FileName, + void checkForDoubleInclude(const FileEntry *File, StringRef FileName, SourceLocation Loc) { - auto It = - std::find_if(Files.rbegin(), Files.rend(), - [&](const Include &Entry) { return Entry.Id == Id; }); + const auto It = + llvm::find_if(llvm::reverse(Files), + [&](const Include &Entry) { return Entry.File == File; }); if (It == Files.rend()) return; - const std::optional<StringRef> FilePath = SM.getNonBuiltinFilenameForID(Id); - if (!FilePath || isFileIgnored(*FilePath)) + const StringRef FilePath = File->tryGetRealPathName(); + if (FilePath.empty() || isFileIgnored(FilePath)) return; if (It == Files.rbegin()) { @@ -144,9 +130,19 @@ public: }); } +#ifndef NDEBUG + void EndOfMainFile() override { + if (!Files.empty() && + Files.back().File == SM.getFileEntryForID(SM.getMainFileID())) + Files.pop_back(); + + assert(Files.empty()); + } +#endif + private: - std::deque<Include> Files; - std::optional<Include> NextToEnter; + std::vector<Include> Files; + SourceLocation NextToEnter; HeaderIncludeCycleCheck &Check; const SourceManager &SM; std::vector<llvm::Regex> IgnoredFilesRegexes; diff --git a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp index 7ea9676..bb8fb240 100644 --- a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp @@ -121,10 +121,11 @@ void UseDesignatedInitializersCheck::registerMatchers(MatchFinder *Finder) { hasAnyBase(hasType(cxxRecordDecl(has(fieldDecl())))); Finder->addMatcher( initListExpr( - hasType(cxxRecordDecl( - RestrictToPODTypes ? isPOD() : isAggregate(), - unless(anyOf(HasBaseWithFields, hasName("::std::array")))) - .bind("type")), + hasType(hasUnqualifiedDesugaredType(recordType(hasDeclaration( + cxxRecordDecl( + RestrictToPODTypes ? isPOD() : isAggregate(), + unless(anyOf(HasBaseWithFields, hasName("::std::array")))) + .bind("type"))))), IgnoreSingleElementAggregates ? hasMoreThanOneElement() : anything(), unless(isFullyDesignated())) .bind("init"), @@ -155,7 +156,7 @@ void UseDesignatedInitializersCheck::check( DiagnosticBuilder Diag = diag(InitList->getLBraceLoc(), "use designated initializer list to initialize %0"); - Diag << Type << InitList->getSourceRange(); + Diag << InitList->getType() << InitList->getSourceRange(); for (const Stmt *InitExpr : *SyntacticInitList) { const auto Designator = Designators[InitExpr->getBeginLoc()]; if (Designator && !Designator->empty()) diff --git a/clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp index 936a906..e307339 100644 --- a/clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp @@ -92,7 +92,7 @@ void UseUsingCheck::check(const MatchFinder::MatchResult &Result) { const LangOptions &LO = getLangOpts(); // Match CXXRecordDecl only to store the range of the last non-implicit full - // declaration, to later check whether it's within the typdef itself. + // declaration, to later check whether it's within the typedef itself. const auto *MatchedTagDecl = Result.Nodes.getNodeAs<TagDecl>(TagDeclName); if (MatchedTagDecl) { // It is not sufficient to just track the last TagDecl that we've seen, @@ -152,7 +152,7 @@ void UseUsingCheck::check(const MatchFinder::MatchResult &Result) { StringRef ExtraReference = ""; if (MainTypeEndLoc.isValid() && TypeRange.fullyContains(MainTypeEndLoc)) { // Each type introduced in a typedef can specify being a reference or - // pointer type seperately, so we need to sigure out if the new using-decl + // pointer type separately, so we need to figure out if the new using-decl // needs to be to a reference or pointer as well. const SourceLocation Tok = utils::lexer::findPreviousAnyTokenKind( MatchedDecl->getLocation(), SM, LO, tok::TokenKind::star, diff --git a/clang-tools-extra/clang-tidy/plugin/ClangTidyPlugin.cpp b/clang-tools-extra/clang-tidy/plugin/ClangTidyPlugin.cpp index 651a63b..195418d 100644 --- a/clang-tools-extra/clang-tidy/plugin/ClangTidyPlugin.cpp +++ b/clang-tools-extra/clang-tidy/plugin/ClangTidyPlugin.cpp @@ -41,7 +41,7 @@ public: new ClangTidyDiagnosticConsumer(*Context, &Compiler.getDiagnostics()); auto DiagOpts = std::make_unique<DiagnosticOptions>(); auto DiagEngine = std::make_unique<DiagnosticsEngine>( - new DiagnosticIDs, *DiagOpts, DiagConsumer); + DiagnosticIDs::create(), *DiagOpts, DiagConsumer); Context->setDiagnosticsEngine(std::move(DiagOpts), DiagEngine.get()); // Create the AST consumer. diff --git a/clang-tools-extra/clang-tidy/portability/TemplateVirtualMemberFunctionCheck.cpp b/clang-tools-extra/clang-tidy/portability/TemplateVirtualMemberFunctionCheck.cpp index 9c2f27f0..aaa2336 100644 --- a/clang-tools-extra/clang-tidy/portability/TemplateVirtualMemberFunctionCheck.cpp +++ b/clang-tools-extra/clang-tidy/portability/TemplateVirtualMemberFunctionCheck.cpp @@ -18,10 +18,11 @@ AST_MATCHER(CXXMethodDecl, isUsed) { return Node.isUsed(); } void TemplateVirtualMemberFunctionCheck::registerMatchers(MatchFinder *Finder) { Finder->addMatcher( - cxxMethodDecl(ofClass(classTemplateSpecializationDecl( + cxxMethodDecl(isVirtual(), + ofClass(classTemplateSpecializationDecl( unless(isExplicitTemplateSpecialization())) .bind("specialization")), - isVirtual(), unless(isUsed()), + unless(isUsed()), unless(isPure()), unless(cxxDestructorDecl(isDefaulted()))) .bind("method"), this); diff --git a/clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp b/clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp index 20c7329..5f19706 100644 --- a/clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp @@ -361,14 +361,15 @@ void ImplicitBoolConversionCheck::check( if (const auto *CastToBool = Result.Nodes.getNodeAs<ImplicitCastExpr>("implicitCastToBool")) { const auto *Parent = Result.Nodes.getNodeAs<Stmt>("parentStmt"); - return handleCastToBool(CastToBool, Parent, *Result.Context); + handleCastToBool(CastToBool, Parent, *Result.Context); + return; } if (const auto *CastFromBool = Result.Nodes.getNodeAs<ImplicitCastExpr>("implicitCastFromBool")) { const auto *NextImplicitCast = Result.Nodes.getNodeAs<ImplicitCastExpr>("furtherImplicitCast"); - return handleCastFromBool(CastFromBool, NextImplicitCast, *Result.Context); + handleCastFromBool(CastFromBool, NextImplicitCast, *Result.Context); } } diff --git a/clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp b/clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp index 91a08b9..561f067 100644 --- a/clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp @@ -106,12 +106,14 @@ QualifiedAutoCheck::QualifiedAutoCheck(StringRef Name, : ClangTidyCheck(Name, Context), AddConstToQualified(Options.get("AddConstToQualified", true)), AllowedTypes( - utils::options::parseStringList(Options.get("AllowedTypes", ""))) {} + utils::options::parseStringList(Options.get("AllowedTypes", ""))), + IgnoreAliasing(Options.get("IgnoreAliasing", true)) {} void QualifiedAutoCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { Options.store(Opts, "AddConstToQualified", AddConstToQualified); Options.store(Opts, "AllowedTypes", utils::options::serializeStringList(AllowedTypes)); + Options.store(Opts, "IgnoreAliasing", IgnoreAliasing); } void QualifiedAutoCheck::registerMatchers(MatchFinder *Finder) { @@ -134,16 +136,30 @@ void QualifiedAutoCheck::registerMatchers(MatchFinder *Finder) { auto IsBoundToType = refersToType(equalsBoundNode("type")); auto UnlessFunctionType = unless(hasUnqualifiedDesugaredType(functionType())); - auto IsAutoDeducedToPointer = [](const std::vector<StringRef> &AllowedTypes, - const auto &...InnerMatchers) { - return autoType(hasDeducedType( - hasUnqualifiedDesugaredType(pointerType(pointee(InnerMatchers...))), - unless(hasUnqualifiedType( - matchers::matchesAnyListedTypeName(AllowedTypes, false))), - unless(pointerType(pointee(hasUnqualifiedType( - matchers::matchesAnyListedTypeName(AllowedTypes, false))))))); + + auto IsPointerType = [this](const auto &...InnerMatchers) { + if (this->IgnoreAliasing) { + return qualType( + hasUnqualifiedDesugaredType(pointerType(pointee(InnerMatchers...)))); + } else { + return qualType( + anyOf(qualType(pointerType(pointee(InnerMatchers...))), + qualType(substTemplateTypeParmType(hasReplacementType( + pointerType(pointee(InnerMatchers...))))))); + } }; + auto IsAutoDeducedToPointer = + [IsPointerType](const std::vector<StringRef> &AllowedTypes, + const auto &...InnerMatchers) { + return autoType(hasDeducedType( + IsPointerType(InnerMatchers...), + unless(hasUnqualifiedType( + matchers::matchesAnyListedTypeName(AllowedTypes, false))), + unless(pointerType(pointee(hasUnqualifiedType( + matchers::matchesAnyListedTypeName(AllowedTypes, false))))))); + }; + Finder->addMatcher( ExplicitSingleVarDecl( hasType(IsAutoDeducedToPointer(AllowedTypes, UnlessFunctionType)), diff --git a/clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.h b/clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.h index 187a4cd..b5b713f 100644 --- a/clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.h +++ b/clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.h @@ -32,6 +32,7 @@ public: private: const bool AddConstToQualified; const std::vector<StringRef> AllowedTypes; + const bool IgnoreAliasing; }; } // namespace clang::tidy::readability diff --git a/clang-tools-extra/clang-tidy/tool/clang-tidy-diff.py b/clang-tools-extra/clang-tidy/tool/clang-tidy-diff.py index 0f8ac73..7cd21af 100755 --- a/clang-tools-extra/clang-tidy/tool/clang-tidy-diff.py +++ b/clang-tools-extra/clang-tidy/tool/clang-tidy-diff.py @@ -177,7 +177,7 @@ def main(): parser.add_argument( "-j", type=int, - default=1, + default=0, help="number of tidy instances to be run in parallel.", ) parser.add_argument( @@ -318,6 +318,7 @@ def main(): if max_task_count == 0: max_task_count = multiprocessing.cpu_count() max_task_count = min(len(lines_by_file), max_task_count) + print(f"Running clang-tidy in {max_task_count} threads...") combine_fixes = False export_fixes_dir = None diff --git a/clang-tools-extra/clang-tidy/tool/run-clang-tidy.py b/clang-tools-extra/clang-tidy/tool/run-clang-tidy.py index 8741147..a3dca6c 100755 --- a/clang-tools-extra/clang-tidy/tool/run-clang-tidy.py +++ b/clang-tools-extra/clang-tidy/tool/run-clang-tidy.py @@ -548,7 +548,7 @@ async def main() -> None: files = {f for f in files if file_name_re.search(f)} print( - "Running clang-tidy for", + f"Running clang-tidy in {max_task} threads for", len(files), "files out of", number_files_in_database, diff --git a/clang-tools-extra/clang-tidy/utils/FormatStringConverter.cpp b/clang-tools-extra/clang-tidy/utils/FormatStringConverter.cpp index 7f4ccca..e1c1bee 100644 --- a/clang-tools-extra/clang-tidy/utils/FormatStringConverter.cpp +++ b/clang-tools-extra/clang-tidy/utils/FormatStringConverter.cpp @@ -207,13 +207,9 @@ FormatStringConverter::FormatStringConverter( ArgsOffset(FormatArgOffset + 1), LangOpts(LO) { assert(ArgsOffset <= NumArgs); FormatExpr = llvm::dyn_cast<StringLiteral>( - Args[FormatArgOffset]->IgnoreImplicitAsWritten()); + Args[FormatArgOffset]->IgnoreUnlessSpelledInSource()); - if (!FormatExpr || !FormatExpr->isOrdinary()) { - // Function must have a narrow string literal as its first argument. - conversionNotPossible("first argument is not a narrow string literal"); - return; - } + assert(FormatExpr && FormatExpr->isOrdinary()); if (const std::optional<StringRef> MaybeMacroName = formatStringContainsUnreplaceableMacro(Call, FormatExpr, SM, PP); diff --git a/clang-tools-extra/clangd/ClangdLSPServer.cpp b/clang-tools-extra/clangd/ClangdLSPServer.cpp index a703009..b445dcf 100644 --- a/clang-tools-extra/clangd/ClangdLSPServer.cpp +++ b/clang-tools-extra/clangd/ClangdLSPServer.cpp @@ -1279,11 +1279,9 @@ void ClangdLSPServer::onHover(const TextDocumentPositionParams &Params, R.contents.kind = HoverContentFormat; R.range = (*H)->SymRange; switch (HoverContentFormat) { - case MarkupKind::PlainText: - R.contents.value = (*H)->present().asPlainText(); - return Reply(std::move(R)); case MarkupKind::Markdown: - R.contents.value = (*H)->present().asMarkdown(); + case MarkupKind::PlainText: + R.contents.value = (*H)->present(HoverContentFormat); return Reply(std::move(R)); }; llvm_unreachable("unhandled MarkupKind"); diff --git a/clang-tools-extra/clangd/CodeComplete.cpp b/clang-tools-extra/clangd/CodeComplete.cpp index 184c3c9..9c17b4c 100644 --- a/clang-tools-extra/clangd/CodeComplete.cpp +++ b/clang-tools-extra/clangd/CodeComplete.cpp @@ -193,7 +193,11 @@ MarkupContent renderDoc(const markup::Document &Doc, MarkupKind Kind) { Result.value.append(Doc.asPlainText()); break; case MarkupKind::Markdown: - Result.value.append(Doc.asMarkdown()); + if (Config::current().Documentation.CommentFormat == + Config::CommentFormatPolicy::PlainText) + Result.value.append(Doc.asEscapedMarkdown()); + else + Result.value.append(Doc.asMarkdown()); break; } return Result; diff --git a/clang-tools-extra/clangd/Config.h b/clang-tools-extra/clangd/Config.h index 83e0fce..2e3e0a4 100644 --- a/clang-tools-extra/clangd/Config.h +++ b/clang-tools-extra/clangd/Config.h @@ -196,6 +196,19 @@ struct Config { /// Controls highlighting modifiers that are disabled. std::vector<std::string> DisabledModifiers; } SemanticTokens; + + enum class CommentFormatPolicy { + /// Treat comments as plain text. + PlainText, + /// Treat comments as Markdown. + Markdown, + /// Treat comments as doxygen. + Doxygen, + }; + + struct { + CommentFormatPolicy CommentFormat = CommentFormatPolicy::PlainText; + } Documentation; }; } // namespace clangd diff --git a/clang-tools-extra/clangd/ConfigCompile.cpp b/clang-tools-extra/clangd/ConfigCompile.cpp index 35d35f7..5dda6dd 100644 --- a/clang-tools-extra/clangd/ConfigCompile.cpp +++ b/clang-tools-extra/clangd/ConfigCompile.cpp @@ -198,6 +198,7 @@ struct FragmentCompiler { compile(std::move(F.InlayHints)); compile(std::move(F.SemanticTokens)); compile(std::move(F.Style)); + compile(std::move(F.Documentation)); } void compile(Fragment::IfBlock &&F) { @@ -793,6 +794,21 @@ struct FragmentCompiler { } } + void compile(Fragment::DocumentationBlock &&F) { + if (F.CommentFormat) { + if (auto Val = + compileEnum<Config::CommentFormatPolicy>("CommentFormat", + *F.CommentFormat) + .map("Plaintext", Config::CommentFormatPolicy::PlainText) + .map("Markdown", Config::CommentFormatPolicy::Markdown) + .map("Doxygen", Config::CommentFormatPolicy::Doxygen) + .value()) + Out.Apply.push_back([Val](const Params &, Config &C) { + C.Documentation.CommentFormat = *Val; + }); + } + } + constexpr static llvm::SourceMgr::DiagKind Error = llvm::SourceMgr::DK_Error; constexpr static llvm::SourceMgr::DiagKind Warning = llvm::SourceMgr::DK_Warning; diff --git a/clang-tools-extra/clangd/ConfigFragment.h b/clang-tools-extra/clangd/ConfigFragment.h index 9e00dbc..a6a7cd5 100644 --- a/clang-tools-extra/clangd/ConfigFragment.h +++ b/clang-tools-extra/clangd/ConfigFragment.h @@ -393,6 +393,17 @@ struct Fragment { std::vector<Located<std::string>> DisabledModifiers; }; SemanticTokensBlock SemanticTokens; + + /// Configures documentation style and behaviour. + struct DocumentationBlock { + /// Specifies the format of comments in the code. + /// Valid values are enum Config::CommentFormatPolicy values: + /// - Plaintext: Treat comments as plain text. + /// - Markdown: Treat comments as Markdown. + /// - Doxygen: Treat comments as doxygen. + std::optional<Located<std::string>> CommentFormat; + }; + DocumentationBlock Documentation; }; } // namespace config diff --git a/clang-tools-extra/clangd/ConfigYAML.cpp b/clang-tools-extra/clangd/ConfigYAML.cpp index 6086357..289b7e8 100644 --- a/clang-tools-extra/clangd/ConfigYAML.cpp +++ b/clang-tools-extra/clangd/ConfigYAML.cpp @@ -69,6 +69,7 @@ public: Dict.handle("Hover", [&](Node &N) { parse(F.Hover, N); }); Dict.handle("InlayHints", [&](Node &N) { parse(F.InlayHints, N); }); Dict.handle("SemanticTokens", [&](Node &N) { parse(F.SemanticTokens, N); }); + Dict.handle("Documentation", [&](Node &N) { parse(F.Documentation, N); }); Dict.parse(N); return !(N.failed() || HadError); } @@ -312,6 +313,15 @@ private: Dict.parse(N); } + void parse(Fragment::DocumentationBlock &F, Node &N) { + DictParser Dict("Documentation", this); + Dict.handle("CommentFormat", [&](Node &N) { + if (auto Value = scalarValue(N, "CommentFormat")) + F.CommentFormat = *Value; + }); + Dict.parse(N); + } + // Helper for parsing mapping nodes (dictionaries). // We don't use YamlIO as we want to control over unknown keys. class DictParser { diff --git a/clang-tools-extra/clangd/FindSymbols.cpp b/clang-tools-extra/clangd/FindSymbols.cpp index 84bcbc1..7655a39 100644 --- a/clang-tools-extra/clangd/FindSymbols.cpp +++ b/clang-tools-extra/clangd/FindSymbols.cpp @@ -14,6 +14,7 @@ #include "SourceCode.h" #include "index/Index.h" #include "support/Logger.h" +#include "clang/AST/DeclFriend.h" #include "clang/AST/DeclTemplate.h" #include "clang/Index/IndexSymbol.h" #include "llvm/ADT/ArrayRef.h" @@ -391,6 +392,17 @@ private: D = TD; } + // FriendDecls don't act as DeclContexts, but they might wrap a function + // definition that won't be visible through other means in the AST. Hence + // unwrap it here instead. + if (auto *Friend = llvm::dyn_cast<FriendDecl>(D)) { + if (auto *Func = + llvm::dyn_cast_or_null<FunctionDecl>(Friend->getFriendDecl())) { + if (Func->isThisDeclarationADefinition()) + D = Func; + } + } + VisitKind Visit = shouldVisit(D); if (Visit == VisitKind::No) return; diff --git a/clang-tools-extra/clangd/Hover.cpp b/clang-tools-extra/clangd/Hover.cpp index e39d8bf..1e0718d 100644 --- a/clang-tools-extra/clangd/Hover.cpp +++ b/clang-tools-extra/clangd/Hover.cpp @@ -15,6 +15,7 @@ #include "Headers.h" #include "IncludeCleaner.h" #include "ParsedAST.h" +#include "Protocol.h" #include "Selection.h" #include "SourceCode.h" #include "clang-include-cleaner/Analysis.h" @@ -960,42 +961,6 @@ std::optional<HoverInfo> getHoverContents(const Attr *A, ParsedAST &AST) { return HI; } -bool isParagraphBreak(llvm::StringRef Rest) { - return Rest.ltrim(" \t").starts_with("\n"); -} - -bool punctuationIndicatesLineBreak(llvm::StringRef Line) { - constexpr llvm::StringLiteral Punctuation = R"txt(.:,;!?)txt"; - - Line = Line.rtrim(); - return !Line.empty() && Punctuation.contains(Line.back()); -} - -bool isHardLineBreakIndicator(llvm::StringRef Rest) { - // '-'/'*' md list, '@'/'\' documentation command, '>' md blockquote, - // '#' headings, '`' code blocks - constexpr llvm::StringLiteral LinebreakIndicators = R"txt(-*@\>#`)txt"; - - Rest = Rest.ltrim(" \t"); - if (Rest.empty()) - return false; - - if (LinebreakIndicators.contains(Rest.front())) - return true; - - if (llvm::isDigit(Rest.front())) { - llvm::StringRef AfterDigit = Rest.drop_while(llvm::isDigit); - if (AfterDigit.starts_with(".") || AfterDigit.starts_with(")")) - return true; - } - return false; -} - -bool isHardLineBreakAfter(llvm::StringRef Line, llvm::StringRef Rest) { - // Should we also consider whether Line is short? - return punctuationIndicatesLineBreak(Line) || isHardLineBreakIndicator(Rest); -} - void addLayoutInfo(const NamedDecl &ND, HoverInfo &HI) { if (ND.isInvalidDecl()) return; @@ -1570,6 +1535,26 @@ markup::Document HoverInfo::present() const { return Output; } +std::string HoverInfo::present(MarkupKind Kind) const { + if (Kind == MarkupKind::Markdown) { + const Config &Cfg = Config::current(); + if ((Cfg.Documentation.CommentFormat == + Config::CommentFormatPolicy::Markdown) || + (Cfg.Documentation.CommentFormat == + Config::CommentFormatPolicy::Doxygen)) + // If the user prefers Markdown, we use the present() method to generate + // the Markdown output. + return present().asMarkdown(); + if (Cfg.Documentation.CommentFormat == + Config::CommentFormatPolicy::PlainText) + // If the user prefers plain text, we use the present() method to generate + // the plain text output. + return present().asEscapedMarkdown(); + } + + return present().asPlainText(); +} + // If the backtick at `Offset` starts a probable quoted range, return the range // (including the quotes). std::optional<llvm::StringRef> getBacktickQuoteRange(llvm::StringRef Line, @@ -1583,9 +1568,14 @@ std::optional<llvm::StringRef> getBacktickQuoteRange(llvm::StringRef Line, return std::nullopt; // The quoted string must be nonempty and usually has no leading/trailing ws. - auto Next = Line.find('`', Offset + 1); + auto Next = Line.find_first_of("`\n", Offset + 1); if (Next == llvm::StringRef::npos) return std::nullopt; + + // There should be no newline in the quoted string. + if (Line[Next] == '\n') + return std::nullopt; + llvm::StringRef Contents = Line.slice(Offset + 1, Next); if (Contents.empty() || isWhitespace(Contents.front()) || isWhitespace(Contents.back())) @@ -1600,51 +1590,40 @@ std::optional<llvm::StringRef> getBacktickQuoteRange(llvm::StringRef Line, return Line.slice(Offset, Next + 1); } -void parseDocumentationLine(llvm::StringRef Line, markup::Paragraph &Out) { +void parseDocumentationParagraph(llvm::StringRef Text, markup::Paragraph &Out) { // Probably this is appendText(Line), but scan for something interesting. - for (unsigned I = 0; I < Line.size(); ++I) { - switch (Line[I]) { + for (unsigned I = 0; I < Text.size(); ++I) { + switch (Text[I]) { case '`': - if (auto Range = getBacktickQuoteRange(Line, I)) { - Out.appendText(Line.substr(0, I)); + if (auto Range = getBacktickQuoteRange(Text, I)) { + Out.appendText(Text.substr(0, I)); Out.appendCode(Range->trim("`"), /*Preserve=*/true); - return parseDocumentationLine(Line.substr(I + Range->size()), Out); + return parseDocumentationParagraph(Text.substr(I + Range->size()), Out); } break; } } - Out.appendText(Line).appendSpace(); + Out.appendText(Text); } void parseDocumentation(llvm::StringRef Input, markup::Document &Output) { - std::vector<llvm::StringRef> ParagraphLines; - auto FlushParagraph = [&] { - if (ParagraphLines.empty()) - return; - auto &P = Output.addParagraph(); - for (llvm::StringRef Line : ParagraphLines) - parseDocumentationLine(Line, P); - ParagraphLines.clear(); - }; - - llvm::StringRef Line, Rest; - for (std::tie(Line, Rest) = Input.split('\n'); - !(Line.empty() && Rest.empty()); - std::tie(Line, Rest) = Rest.split('\n')) { - - // After a linebreak remove spaces to avoid 4 space markdown code blocks. - // FIXME: make FlushParagraph handle this. - Line = Line.ltrim(); - if (!Line.empty()) - ParagraphLines.push_back(Line); - - if (isParagraphBreak(Rest) || isHardLineBreakAfter(Line, Rest)) { - FlushParagraph(); - } + // A documentation string is treated as a sequence of paragraphs, + // where the paragraphs are seperated by at least one empty line + // (meaning 2 consecutive newline characters). + // Possible leading empty lines (introduced by an odd number > 1 of + // empty lines between 2 paragraphs) will be removed later in the Markup + // renderer. + llvm::StringRef Paragraph, Rest; + for (std::tie(Paragraph, Rest) = Input.split("\n\n"); + !(Paragraph.empty() && Rest.empty()); + std::tie(Paragraph, Rest) = Rest.split("\n\n")) { + + // The Paragraph will be empty if there is an even number of newline + // characters between two paragraphs, so we skip it. + if (!Paragraph.empty()) + parseDocumentationParagraph(Paragraph, Output.addParagraph()); } - FlushParagraph(); } - llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const HoverInfo::PrintedType &T) { OS << T.Type; diff --git a/clang-tools-extra/clangd/Hover.h b/clang-tools-extra/clangd/Hover.h index fe689de..2f65431 100644 --- a/clang-tools-extra/clangd/Hover.h +++ b/clang-tools-extra/clangd/Hover.h @@ -120,6 +120,8 @@ struct HoverInfo { /// Produce a user-readable information. markup::Document present() const; + + std::string present(MarkupKind Kind) const; }; inline bool operator==(const HoverInfo::PrintedType &LHS, diff --git a/clang-tools-extra/clangd/Preamble.cpp b/clang-tools-extra/clangd/Preamble.cpp index 7b4d63f..8af9e46 100644 --- a/clang-tools-extra/clangd/Preamble.cpp +++ b/clang-tools-extra/clangd/Preamble.cpp @@ -659,7 +659,7 @@ buildPreamble(PathRef FileName, CompilerInvocation CI, WallTimer PreambleTimer; PreambleTimer.startTimer(); auto BuiltPreamble = PrecompiledPreamble::Build( - CI, ContentsBuffer.get(), Bounds, *PreambleDiagsEngine, + CI, ContentsBuffer.get(), Bounds, PreambleDiagsEngine, Stats ? TimedFS : StatCacheFS, std::make_shared<PCHContainerOperations>(), StoreInMemory, /*StoragePath=*/"", CapturedInfo); diff --git a/clang-tools-extra/clangd/SystemIncludeExtractor.cpp b/clang-tools-extra/clangd/SystemIncludeExtractor.cpp index 0b067e8..106de1b 100644 --- a/clang-tools-extra/clangd/SystemIncludeExtractor.cpp +++ b/clang-tools-extra/clangd/SystemIncludeExtractor.cpp @@ -254,7 +254,7 @@ bool isValidTarget(llvm::StringRef Triple) { std::shared_ptr<TargetOptions> TargetOpts(new TargetOptions); TargetOpts->Triple = Triple.str(); DiagnosticOptions DiagOpts; - DiagnosticsEngine Diags(new DiagnosticIDs, DiagOpts, + DiagnosticsEngine Diags(DiagnosticIDs::create(), DiagOpts, new IgnoringDiagConsumer); llvm::IntrusiveRefCntPtr<TargetInfo> Target = TargetInfo::CreateTargetInfo(Diags, *TargetOpts); diff --git a/clang-tools-extra/clangd/support/Markup.cpp b/clang-tools-extra/clangd/support/Markup.cpp index 63aff96..a130830 100644 --- a/clang-tools-extra/clangd/support/Markup.cpp +++ b/clang-tools-extra/clangd/support/Markup.cpp @@ -6,12 +6,12 @@ // //===----------------------------------------------------------------------===// #include "support/Markup.h" +#include "clang/Basic/CharInfo.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" -#include "llvm/Support/Compiler.h" #include "llvm/Support/raw_ostream.h" #include <cstddef> #include <iterator> @@ -64,8 +64,8 @@ bool looksLikeTag(llvm::StringRef Contents) { // It's always safe to escape punctuation, but want minimal escaping. // The strategy is to escape the first character of anything that might start // a markdown grammar construct. -bool needsLeadingEscape(char C, llvm::StringRef Before, llvm::StringRef After, - bool StartsLine) { +bool needsLeadingEscapePlaintext(char C, llvm::StringRef Before, + llvm::StringRef After, bool StartsLine) { assert(Before.take_while(llvm::isSpace).empty()); auto RulerLength = [&]() -> /*Length*/ unsigned { if (!StartsLine || !Before.empty()) @@ -151,16 +151,94 @@ bool needsLeadingEscape(char C, llvm::StringRef Before, llvm::StringRef After, } } -/// Escape a markdown text block. Ensures the punctuation will not introduce +/// \brief Tests whether \p C should be backslash-escaped in markdown. +/// +/// The MarkupContent LSP specification defines that `markdown` content needs to +/// follow GFM (GitHub Flavored Markdown) rules. And we can assume that markdown +/// is rendered on the client side. This means we do not need to escape any +/// markdown constructs. +/// The only exception is when the client does not support HTML rendering in +/// markdown. In that case, we need to escape HTML tags and HTML entities. +/// +/// **FIXME:** handle the case when the client does support HTML rendering in +/// markdown. For this, the LSP server needs to check the +/// [supportsHtml +/// capability](https://github.com/microsoft/language-server-protocol/issues/1344) +/// of the client. +/// +/// \param C The character to check. +/// \param After The string that follows \p C . +/// This is used to determine if \p C is part of a tag or an entity reference. +/// +/// \returns true if \p C should be escaped, false otherwise. +bool needsLeadingEscapeMarkdown(char C, llvm::StringRef After) { + switch (C) { + case '<': // HTML tag (or autolink, which we choose not to escape) + return looksLikeTag(After); + case '&': { // HTML entity reference + auto End = After.find(';'); + if (End == llvm::StringRef::npos) + return false; + llvm::StringRef Content = After.substr(0, End); + if (Content.consume_front("#")) { + if (Content.consume_front("x") || Content.consume_front("X")) + return llvm::all_of(Content, llvm::isHexDigit); + return llvm::all_of(Content, llvm::isDigit); + } + return llvm::all_of(Content, llvm::isAlpha); + } + default: + return false; + } +} + +bool needsLeadingEscape(char C, llvm::StringRef Before, llvm::StringRef After, + bool StartsLine, bool EscapeMarkdown) { + if (EscapeMarkdown) + return needsLeadingEscapePlaintext(C, Before, After, StartsLine); + return needsLeadingEscapeMarkdown(C, After); +} + +/// Escape a markdown text block. +/// If \p EscapeMarkdown is true it ensures the punctuation will not introduce /// any of the markdown constructs. -std::string renderText(llvm::StringRef Input, bool StartsLine) { +/// Else, markdown syntax is not escaped, only HTML tags and entities. +std::string renderText(llvm::StringRef Input, bool StartsLine, + bool EscapeMarkdown) { std::string R; - for (unsigned I = 0; I < Input.size(); ++I) { - if (needsLeadingEscape(Input[I], Input.substr(0, I), Input.substr(I + 1), - StartsLine)) - R.push_back('\\'); - R.push_back(Input[I]); + R.reserve(Input.size()); + + // split the input into lines, and escape each line separately. + llvm::StringRef Line, Rest; + + bool IsFirstLine = true; + + for (std::tie(Line, Rest) = Input.split('\n'); + !(Line.empty() && Rest.empty()); + std::tie(Line, Rest) = Rest.split('\n')) { + + bool StartsLineIntern = IsFirstLine ? StartsLine : true; + + // Ignore leading spaces for the escape logic, but preserve them in the + // output. + StringRef LeadingSpaces = Line.take_while(llvm::isSpace); + if (!LeadingSpaces.empty()) { + R.append(LeadingSpaces); + } + + for (unsigned I = LeadingSpaces.size(); I < Line.size(); ++I) { + if (needsLeadingEscape(Line[I], Line.substr(LeadingSpaces.size(), I), + Line.substr(I + 1), StartsLineIntern, + EscapeMarkdown)) + R.push_back('\\'); + R.push_back(Line[I]); + } + + IsFirstLine = false; + if (!Rest.empty()) + R.push_back('\n'); } + return R; } @@ -168,6 +246,7 @@ std::string renderText(llvm::StringRef Input, bool StartsLine) { /// is surrounded by backticks and the inner contents are properly escaped. std::string renderInlineBlock(llvm::StringRef Input) { std::string R; + R.reserve(Input.size()); // Double all backticks to make sure we don't close the inline block early. for (size_t From = 0; From < Input.size();) { size_t Next = Input.find("`", From); @@ -261,6 +340,9 @@ std::string renderBlocks(llvm::ArrayRef<std::unique_ptr<Block>> Children, // https://github.com/microsoft/vscode/issues/88416 for details. class Ruler : public Block { public: + void renderEscapedMarkdown(llvm::raw_ostream &OS) const override { + renderMarkdown(OS); + } void renderMarkdown(llvm::raw_ostream &OS) const override { // Note that we need an extra new line before the ruler, otherwise we might // make previous block a title instead of introducing a ruler. @@ -275,6 +357,9 @@ public: class CodeBlock : public Block { public: + void renderEscapedMarkdown(llvm::raw_ostream &OS) const override { + renderMarkdown(OS); + } void renderMarkdown(llvm::raw_ostream &OS) const override { std::string Marker = getMarkerForCodeBlock(Contents); // No need to pad from previous blocks, as they should end with a new line. @@ -303,11 +388,13 @@ private: std::string indentLines(llvm::StringRef Input) { assert(!Input.ends_with("\n") && "Input should've been trimmed."); std::string IndentedR; - // We'll add 2 spaces after each new line. + // We'll add 2 spaces after each new line which is not followed by another new + // line. IndentedR.reserve(Input.size() + Input.count('\n') * 2); - for (char C : Input) { + for (size_t I = 0; I < Input.size(); ++I) { + char C = Input[I]; IndentedR += C; - if (C == '\n') + if (C == '\n' && (((I + 1) < Input.size()) && (Input[I + 1] != '\n'))) IndentedR.append(" "); } return IndentedR; @@ -316,17 +403,34 @@ std::string indentLines(llvm::StringRef Input) { class Heading : public Paragraph { public: Heading(size_t Level) : Level(Level) {} + + void renderEscapedMarkdown(llvm::raw_ostream &OS) const override { + insertHeadingMarkers(OS); + Paragraph::renderEscapedMarkdown(OS); + } + void renderMarkdown(llvm::raw_ostream &OS) const override { - OS << std::string(Level, '#') << ' '; + insertHeadingMarkers(OS); Paragraph::renderMarkdown(OS); } private: size_t Level; + + void insertHeadingMarkers(llvm::raw_ostream &OS) const { + OS << std::string(Level, '#') << ' '; + } }; } // namespace +std::string Block::asEscapedMarkdown() const { + std::string R; + llvm::raw_string_ostream OS(R); + renderEscapedMarkdown(OS); + return llvm::StringRef(OS.str()).trim().str(); +} + std::string Block::asMarkdown() const { std::string R; llvm::raw_string_ostream OS(R); @@ -341,6 +445,35 @@ std::string Block::asPlainText() const { return llvm::StringRef(OS.str()).trim().str(); } +void Paragraph::renderEscapedMarkdown(llvm::raw_ostream &OS) const { + bool NeedsSpace = false; + bool HasChunks = false; + for (auto &C : Chunks) { + if (C.SpaceBefore || NeedsSpace) + OS << " "; + switch (C.Kind) { + case ChunkKind::PlainText: + OS << renderText(C.Contents, !HasChunks, /*EscapeMarkdown=*/true); + break; + case ChunkKind::InlineCode: + OS << renderInlineBlock(C.Contents); + break; + case ChunkKind::Bold: + OS << renderText("**" + C.Contents + "**", !HasChunks, + /*EscapeMarkdown=*/true); + break; + case ChunkKind::Emphasized: + OS << renderText("*" + C.Contents + "*", !HasChunks, + /*EscapeMarkdown=*/true); + break; + } + HasChunks = true; + NeedsSpace = C.SpaceAfter; + } + // A paragraph in markdown is separated by a blank line. + OS << "\n\n"; +} + void Paragraph::renderMarkdown(llvm::raw_ostream &OS) const { bool NeedsSpace = false; bool HasChunks = false; @@ -348,20 +481,26 @@ void Paragraph::renderMarkdown(llvm::raw_ostream &OS) const { if (C.SpaceBefore || NeedsSpace) OS << " "; switch (C.Kind) { - case Chunk::PlainText: - OS << renderText(C.Contents, !HasChunks); + case ChunkKind::PlainText: + OS << renderText(C.Contents, !HasChunks, /*EscapeMarkdown=*/false); break; - case Chunk::InlineCode: + case ChunkKind::InlineCode: OS << renderInlineBlock(C.Contents); break; + case ChunkKind::Bold: + OS << "**" << renderText(C.Contents, !HasChunks, /*EscapeMarkdown=*/false) + << "**"; + break; + case ChunkKind::Emphasized: + OS << "*" << renderText(C.Contents, !HasChunks, /*EscapeMarkdown=*/false) + << "*"; + break; } HasChunks = true; NeedsSpace = C.SpaceAfter; } - // Paragraphs are translated into markdown lines, not markdown paragraphs. - // Therefore it only has a single linebreak afterwards. - // VSCode requires two spaces at the end of line to start a new one. - OS << " \n"; + // A paragraph in markdown is separated by a blank line. + OS << "\n\n"; } std::unique_ptr<Block> Paragraph::clone() const { @@ -370,8 +509,8 @@ std::unique_ptr<Block> Paragraph::clone() const { /// Choose a marker to delimit `Text` from a prioritized list of options. /// This is more readable than escaping for plain-text. -llvm::StringRef chooseMarker(llvm::ArrayRef<llvm::StringRef> Options, - llvm::StringRef Text) { +llvm::StringRef Paragraph::chooseMarker(llvm::ArrayRef<llvm::StringRef> Options, + llvm::StringRef Text) const { // Prefer a delimiter whose characters don't appear in the text. for (llvm::StringRef S : Options) if (Text.find_first_of(S) == llvm::StringRef::npos) @@ -379,31 +518,147 @@ llvm::StringRef chooseMarker(llvm::ArrayRef<llvm::StringRef> Options, return Options.front(); } +bool Paragraph::punctuationIndicatesLineBreak(llvm::StringRef Line) const { + constexpr llvm::StringLiteral Punctuation = R"txt(.:,;!?)txt"; + + Line = Line.rtrim(); + return !Line.empty() && Punctuation.contains(Line.back()); +} + +bool Paragraph::isHardLineBreakIndicator(llvm::StringRef Rest) const { + // '-'/'*' md list, '@'/'\' documentation command, '>' md blockquote, + // '#' headings, '`' code blocks, two spaces (markdown force newline) + constexpr llvm::StringLiteral LinebreakIndicators = R"txt(-*@\>#`)txt"; + + Rest = Rest.ltrim(" \t"); + if (Rest.empty()) + return false; + + if (LinebreakIndicators.contains(Rest.front())) + return true; + + if (llvm::isDigit(Rest.front())) { + llvm::StringRef AfterDigit = Rest.drop_while(llvm::isDigit); + if (AfterDigit.starts_with(".") || AfterDigit.starts_with(")")) + return true; + } + return false; +} + +bool Paragraph::isHardLineBreakAfter(llvm::StringRef Line, + llvm::StringRef Rest) const { + // In Markdown, 2 spaces before a line break forces a line break. + // Add a line break for plaintext in this case too. + // Should we also consider whether Line is short? + return Line.ends_with(" ") || punctuationIndicatesLineBreak(Line) || + isHardLineBreakIndicator(Rest); +} + void Paragraph::renderPlainText(llvm::raw_ostream &OS) const { bool NeedsSpace = false; + std::string ConcatenatedText; + ConcatenatedText.reserve(EstimatedStringSize); + + llvm::raw_string_ostream ConcatenatedOS(ConcatenatedText); + for (auto &C : Chunks) { + + if (C.Kind == ChunkKind::PlainText) { + if (C.SpaceBefore || NeedsSpace) + ConcatenatedOS << ' '; + + ConcatenatedOS << C.Contents; + NeedsSpace = llvm::isSpace(C.Contents.back()) || C.SpaceAfter; + continue; + } + if (C.SpaceBefore || NeedsSpace) - OS << " "; + ConcatenatedOS << ' '; llvm::StringRef Marker = ""; - if (C.Preserve && C.Kind == Chunk::InlineCode) + if (C.Preserve && C.Kind == ChunkKind::InlineCode) Marker = chooseMarker({"`", "'", "\""}, C.Contents); - OS << Marker << C.Contents << Marker; + else if (C.Kind == ChunkKind::Bold) + Marker = "**"; + else if (C.Kind == ChunkKind::Emphasized) + Marker = "*"; + ConcatenatedOS << Marker << C.Contents << Marker; NeedsSpace = C.SpaceAfter; } - OS << '\n'; + + // We go through the contents line by line to handle the newlines + // and required spacing correctly. + // + // Newlines are added if: + // - the line ends with 2 spaces and a newline follows + // - the line ends with punctuation that indicates a line break (.:,;!?) + // - the next line starts with a hard line break indicator (-@>#`, or a digit + // followed by '.' or ')'), ignoring leading whitespace. + // + // Otherwise, newlines in the input are replaced with a single space. + // + // Multiple spaces are collapsed into a single space. + // + // Lines containing only whitespace are ignored. + llvm::StringRef Line, Rest; + + for (std::tie(Line, Rest) = + llvm::StringRef(ConcatenatedText).trim().split('\n'); + !(Line.empty() && Rest.empty()); + std::tie(Line, Rest) = Rest.split('\n')) { + + // Remove lines which only contain whitespace. + // + // Note: this also handles the case when there are multiple newlines + // in a row, since all leading newlines are removed. + // + // The documentation parsing treats multiple newlines as paragraph + // separators, hence it will create a new Paragraph instead of adding + // multiple newlines to the same Paragraph. + // Therfore multiple newlines are never added to a paragraph + // except if the user explicitly adds them using + // e.g. appendText("user text\n\nnext text"). + Line = Line.ltrim(); + if (Line.empty()) + continue; + + OS << canonicalizeSpaces(Line); + + if (isHardLineBreakAfter(Line, Rest)) + OS << '\n'; + else if (!Rest.empty()) + // Since we removed any trailing whitespace from the input using trim(), + // we know that the next line contains non-whitespace characters. + // Therefore, we can add a space without worrying about trailing spaces. + OS << ' '; + } + + // Paragraphs are separated by a blank line. + OS << "\n\n"; } BulletList::BulletList() = default; BulletList::~BulletList() = default; +void BulletList::renderEscapedMarkdown(llvm::raw_ostream &OS) const { + for (auto &D : Items) { + std::string M = D.asEscapedMarkdown(); + // Instead of doing this we might prefer passing Indent to children to get + // rid of the copies, if it turns out to be a bottleneck. + OS << "- " << indentLines(M) << '\n'; + } + // We add 2 newlines after list to terminate it in markdown. + OS << "\n\n"; +} + void BulletList::renderMarkdown(llvm::raw_ostream &OS) const { for (auto &D : Items) { + std::string M = D.asMarkdown(); // Instead of doing this we might prefer passing Indent to children to get // rid of the copies, if it turns out to be a bottleneck. - OS << "- " << indentLines(D.asMarkdown()) << '\n'; + OS << "- " << indentLines(M) << '\n'; } - // We need a new line after list to terminate it in markdown. - OS << '\n'; + // We add 2 newlines after list to terminate it in markdown. + OS << "\n\n"; } void BulletList::renderPlainText(llvm::raw_ostream &OS) const { @@ -412,6 +667,7 @@ void BulletList::renderPlainText(llvm::raw_ostream &OS) const { // rid of the copies, if it turns out to be a bottleneck. OS << "- " << indentLines(D.asPlainText()) << '\n'; } + OS << '\n'; } Paragraph &Paragraph::appendSpace() { @@ -420,32 +676,51 @@ Paragraph &Paragraph::appendSpace() { return *this; } -Paragraph &Paragraph::appendText(llvm::StringRef Text) { - std::string Norm = canonicalizeSpaces(Text); - if (Norm.empty()) +Paragraph &Paragraph::appendChunk(llvm::StringRef Contents, ChunkKind K) { + if (Contents.empty()) return *this; Chunks.emplace_back(); Chunk &C = Chunks.back(); - C.Contents = std::move(Norm); - C.Kind = Chunk::PlainText; - C.SpaceBefore = llvm::isSpace(Text.front()); - C.SpaceAfter = llvm::isSpace(Text.back()); + C.Contents = Contents; + C.Kind = K; + + EstimatedStringSize += Contents.size(); return *this; } +Paragraph &Paragraph::appendText(llvm::StringRef Text) { + if (!Chunks.empty() && Chunks.back().Kind == ChunkKind::PlainText) { + Chunks.back().Contents += std::move(Text); + return *this; + } + + return appendChunk(std::move(Text), ChunkKind::PlainText); +} + +Paragraph &Paragraph::appendEmphasizedText(llvm::StringRef Text) { + return appendChunk(canonicalizeSpaces(std::move(Text)), + ChunkKind::Emphasized); +} + +Paragraph &Paragraph::appendBoldText(llvm::StringRef Text) { + return appendChunk(canonicalizeSpaces(std::move(Text)), ChunkKind::Bold); +} + Paragraph &Paragraph::appendCode(llvm::StringRef Code, bool Preserve) { bool AdjacentCode = - !Chunks.empty() && Chunks.back().Kind == Chunk::InlineCode; + !Chunks.empty() && Chunks.back().Kind == ChunkKind::InlineCode; std::string Norm = canonicalizeSpaces(std::move(Code)); if (Norm.empty()) return *this; + EstimatedStringSize += Norm.size(); Chunks.emplace_back(); Chunk &C = Chunks.back(); C.Contents = std::move(Norm); - C.Kind = Chunk::InlineCode; + C.Kind = ChunkKind::InlineCode; C.Preserve = Preserve; // Disallow adjacent code spans without spaces, markdown can't render them. C.SpaceBefore = AdjacentCode; + return *this; } @@ -482,6 +757,10 @@ void Document::addCodeBlock(std::string Code, std::string Language) { std::make_unique<CodeBlock>(std::move(Code), std::move(Language))); } +std::string Document::asEscapedMarkdown() const { + return renderBlocks(Children, &Block::renderEscapedMarkdown); +} + std::string Document::asMarkdown() const { return renderBlocks(Children, &Block::renderMarkdown); } diff --git a/clang-tools-extra/clangd/support/Markup.h b/clang-tools-extra/clangd/support/Markup.h index 3a869c4..eea6328 100644 --- a/clang-tools-extra/clangd/support/Markup.h +++ b/clang-tools-extra/clangd/support/Markup.h @@ -27,9 +27,11 @@ namespace markup { /// should trim them if need be. class Block { public: + virtual void renderEscapedMarkdown(llvm::raw_ostream &OS) const = 0; virtual void renderMarkdown(llvm::raw_ostream &OS) const = 0; virtual void renderPlainText(llvm::raw_ostream &OS) const = 0; virtual std::unique_ptr<Block> clone() const = 0; + std::string asEscapedMarkdown() const; std::string asMarkdown() const; std::string asPlainText() const; @@ -42,6 +44,7 @@ public: /// One must introduce different paragraphs to create separate blocks. class Paragraph : public Block { public: + void renderEscapedMarkdown(llvm::raw_ostream &OS) const override; void renderMarkdown(llvm::raw_ostream &OS) const override; void renderPlainText(llvm::raw_ostream &OS) const override; std::unique_ptr<Block> clone() const override; @@ -49,6 +52,12 @@ public: /// Append plain text to the end of the string. Paragraph &appendText(llvm::StringRef Text); + /// Append emphasized text, this translates to the * block in markdown. + Paragraph &appendEmphasizedText(llvm::StringRef Text); + + /// Append bold text, this translates to the ** block in markdown. + Paragraph &appendBoldText(llvm::StringRef Text); + /// Append inline code, this translates to the ` block in markdown. /// \p Preserve indicates the code span must be apparent even in plaintext. Paragraph &appendCode(llvm::StringRef Code, bool Preserve = false); @@ -58,11 +67,9 @@ public: Paragraph &appendSpace(); private: + enum ChunkKind { PlainText, InlineCode, Bold, Emphasized }; struct Chunk { - enum { - PlainText, - InlineCode, - } Kind = PlainText; + ChunkKind Kind = PlainText; // Preserve chunk markers in plaintext. bool Preserve = false; std::string Contents; @@ -73,6 +80,21 @@ private: bool SpaceAfter = false; }; std::vector<Chunk> Chunks; + + /// Estimated size of the string representation of this paragraph. + /// Used to reserve space in the output string. + /// Each time paragraph content is added, this value is updated. + /// This is an estimate, so it may not be accurate but can help + /// reducing dynamically reallocating string memory. + unsigned EstimatedStringSize = 0; + + Paragraph &appendChunk(llvm::StringRef Contents, ChunkKind K); + + llvm::StringRef chooseMarker(llvm::ArrayRef<llvm::StringRef> Options, + llvm::StringRef Text) const; + bool punctuationIndicatesLineBreak(llvm::StringRef Line) const; + bool isHardLineBreakIndicator(llvm::StringRef Rest) const; + bool isHardLineBreakAfter(llvm::StringRef Line, llvm::StringRef Rest) const; }; /// Represents a sequence of one or more documents. Knows how to print them in a @@ -82,6 +104,10 @@ public: BulletList(); ~BulletList(); + // A BulletList rendered in markdown is a tight list if it is not a nested + // list and no item contains multiple paragraphs. Otherwise, it is a loose + // list. + void renderEscapedMarkdown(llvm::raw_ostream &OS) const override; void renderMarkdown(llvm::raw_ostream &OS) const override; void renderPlainText(llvm::raw_ostream &OS) const override; std::unique_ptr<Block> clone() const override; @@ -117,9 +143,13 @@ public: BulletList &addBulletList(); + /// Doesn't contain any trailing newlines and escaped markdown syntax. + /// It is expected that the result of this function + /// is rendered as markdown. + std::string asEscapedMarkdown() const; /// Doesn't contain any trailing newlines. - /// We try to make the markdown human-readable, e.g. avoid extra escaping. - /// At least one client (coc.nvim) displays the markdown verbatim! + /// It is expected that the result of this function + /// is rendered as markdown. std::string asMarkdown() const; /// Doesn't contain any trailing newlines. std::string asPlainText() const; diff --git a/clang-tools-extra/clangd/test/signature-help-unescaped.test b/clang-tools-extra/clangd/test/signature-help-unescaped.test new file mode 100644 index 0000000..c8a7df8 --- /dev/null +++ b/clang-tools-extra/clangd/test/signature-help-unescaped.test @@ -0,0 +1,40 @@ +# We specify a custom path in XDG_CONFIG_HOME, which only works on some systems. +# UNSUPPORTED: system-windows +# UNSUPPORTED: system-darwin + +# RUN: mkdir -p %t/clangd + +# Create a config file that configures to use CommentFormat Markdown. +# RUN: echo 'Documentation:' > %t/clangd/config.yaml +# RUN: echo ' CommentFormat: Markdown' >> %t/clangd/config.yaml +# RUN: env XDG_CONFIG_HOME=%t clangd -lit-test -enable-config < %s | FileCheck -strict-whitespace %s +# Start a session. +{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{"textDocument": {"signatureHelp": {"signatureInformation": {"documentationFormat": ["markdown", "plaintext"]}}}},"trace":"off"}} +--- +{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"test:///main.cpp","languageId":"cpp","version":1,"text":"// comment `markdown` _noescape_\nvoid x(int);\nint main(){\nx("}}} +--- +{"jsonrpc":"2.0","id":1,"method":"textDocument/signatureHelp","params":{"textDocument":{"uri":"test:///main.cpp"},"position":{"line":3,"character":2}}} +# CHECK: "id": 1, +# CHECK-NEXT: "jsonrpc": "2.0", +# CHECK-NEXT: "result": { +# CHECK-NEXT: "activeParameter": 0, +# CHECK-NEXT: "activeSignature": 0, +# CHECK-NEXT: "signatures": [ +# CHECK-NEXT: { +# CHECK-NEXT: "documentation": { +# CHECK-NEXT: "kind": "markdown", +# CHECK-NEXT: "value": "comment `markdown` _noescape_" +# CHECK-NEXT: }, +# CHECK-NEXT: "label": "x(int) -> void", +# CHECK-NEXT: "parameters": [ +# CHECK-NEXT: { +# CHECK-NEXT: "label": "int" +# CHECK-NEXT: } +# CHECK-NEXT: ] +# CHECK-NEXT: } +# CHECK-NEXT: ] +# CHECK-NEXT: } +--- +{"jsonrpc":"2.0","id":100000,"method":"shutdown"} +--- +{"jsonrpc":"2.0","method":"exit"} diff --git a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp index b7c64c7..61bd631 100644 --- a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp +++ b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp @@ -1095,10 +1095,11 @@ TEST(CompletionTest, Documentation) { int x = ^ )cpp"); - EXPECT_THAT(Results.Completions, - Contains(AllOf( - named("foo"), - doc("Annotation: custom_annotation\nNon-doxygen comment.")))); + EXPECT_THAT( + Results.Completions, + Contains( + AllOf(named("foo"), + doc("Annotation: custom_annotation\n\nNon-doxygen comment.")))); EXPECT_THAT( Results.Completions, Contains(AllOf(named("bar"), doc("Doxygen comment.\n\\param int a")))); @@ -2297,7 +2298,7 @@ TEST(CompletionTest, Render) { EXPECT_EQ(R.insertTextFormat, InsertTextFormat::PlainText); EXPECT_EQ(R.filterText, "x"); EXPECT_EQ(R.detail, "int"); - EXPECT_EQ(R.documentation->value, "From \"foo.h\"\nThis is x()"); + EXPECT_EQ(R.documentation->value, "From \"foo.h\"\n\nThis is x()"); EXPECT_THAT(R.additionalTextEdits, IsEmpty()); EXPECT_EQ(R.sortText, sortText(1.0, "x")); EXPECT_FALSE(R.deprecated); @@ -2332,7 +2333,7 @@ TEST(CompletionTest, Render) { C.BundleSize = 2; R = C.render(Opts); EXPECT_EQ(R.detail, "[2 overloads]"); - EXPECT_EQ(R.documentation->value, "From \"foo.h\"\nThis is x()"); + EXPECT_EQ(R.documentation->value, "From \"foo.h\"\n\nThis is x()"); C.Deprecated = true; R = C.render(Opts); @@ -2340,7 +2341,7 @@ TEST(CompletionTest, Render) { Opts.DocumentationFormat = MarkupKind::Markdown; R = C.render(Opts); - EXPECT_EQ(R.documentation->value, "From `\"foo.h\"` \nThis is `x()`"); + EXPECT_EQ(R.documentation->value, "From `\"foo.h\"`\n\nThis is `x()`"); } TEST(CompletionTest, IgnoreRecoveryResults) { @@ -3266,6 +3267,56 @@ TEST(SignatureHelpTest, VariadicType) { } } +TEST(SignatureHelpTest, SkipExplicitObjectParameter) { + Annotations Code(R"cpp( + struct A { + void foo(this auto&& self, int arg); + void bar(this A self, int arg); + }; + int main() { + A a {}; + a.foo($c1^); + (&A::bar)($c2^); + (&A::foo)($c3^); + } + )cpp"); + + auto TU = TestTU::withCode(Code.code()); + TU.ExtraArgs = {"-std=c++23"}; + + MockFS FS; + auto Inputs = TU.inputs(FS); + + auto Preamble = TU.preamble(); + ASSERT_TRUE(Preamble); + + { + const auto Result = signatureHelp(testPath(TU.Filename), Code.point("c1"), + *Preamble, Inputs, MarkupKind::PlainText); + + EXPECT_EQ(1U, Result.signatures.size()); + + EXPECT_THAT(Result.signatures[0], AllOf(sig("foo([[int arg]]) -> void"))); + } + { + const auto Result = signatureHelp(testPath(TU.Filename), Code.point("c2"), + *Preamble, Inputs, MarkupKind::PlainText); + + EXPECT_EQ(1U, Result.signatures.size()); + + EXPECT_THAT(Result.signatures[0], AllOf(sig("([[A]], [[int]]) -> void"))); + } + { + // TODO: llvm/llvm-project/146649 + const auto Result = signatureHelp(testPath(TU.Filename), Code.point("c3"), + *Preamble, Inputs, MarkupKind::PlainText); + // TODO: We expect 1 signature here, with this signature + EXPECT_EQ(0U, Result.signatures.size()); + // EXPECT_THAT(Result.signatures[0], AllOf(sig("([[auto&&]], [[int]]) -> + // void"))); + } +} + TEST(CompletionTest, IncludedCompletionKinds) { Annotations Test(R"cpp(#include "^)cpp"); auto TU = TestTU::withCode(Test.code()); @@ -4368,14 +4419,24 @@ TEST(CompletionTest, SkipExplicitObjectParameter) { Annotations Code(R"cpp( struct A { void foo(this auto&& self, int arg); + void bar(this A self, int arg); }; int main() { A a {}; - a.^ + a.$c1^; + (&A::fo$c2^; + (&A::ba$c3^; } )cpp"); + // TODO: llvm/llvm-project/146649 + // This is incorrect behavior. Correct Result should be a variant of, + // c2: signature = (auto&& self, int arg) + // snippet = (${1: auto&& self}, ${2: int arg}) + // c3: signature = (A self, int arg) + // snippet = (${1: A self}, ${2: int arg}) + auto TU = TestTU::withCode(Code.code()); TU.ExtraArgs = {"-std=c++23"}; @@ -4386,12 +4447,31 @@ TEST(CompletionTest, SkipExplicitObjectParameter) { MockFS FS; auto Inputs = TU.inputs(FS); - auto Result = codeComplete(testPath(TU.Filename), Code.point(), - Preamble.get(), Inputs, Opts); - - EXPECT_THAT(Result.Completions, - ElementsAre(AllOf(named("foo"), signature("(int arg)"), - snippetSuffix("(${1:int arg})")))); + { + auto Result = codeComplete(testPath(TU.Filename), Code.point("c1"), + Preamble.get(), Inputs, Opts); + + EXPECT_THAT(Result.Completions, + UnorderedElementsAre(AllOf(named("foo"), signature("(int arg)"), + snippetSuffix("(${1:int arg})")), + AllOf(named("bar"), signature("(int arg)"), + snippetSuffix("(${1:int arg})")))); + } + { + auto Result = codeComplete(testPath(TU.Filename), Code.point("c2"), + Preamble.get(), Inputs, Opts); + EXPECT_THAT( + Result.Completions, + ElementsAre(AllOf(named("foo"), signature("<class self:auto>(int arg)"), + snippetSuffix("<${1:class self:auto}>")))); + } + { + auto Result = codeComplete(testPath(TU.Filename), Code.point("c3"), + Preamble.get(), Inputs, Opts); + EXPECT_THAT(Result.Completions, + ElementsAre(AllOf(named("bar"), signature("(int arg)"), + snippetSuffix("")))); + } } } // namespace } // namespace clangd diff --git a/clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp b/clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp index 75d0ff2..0e411b2 100644 --- a/clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp +++ b/clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp @@ -299,7 +299,7 @@ TEST_F(ConfigCompileTests, DiagnosticSuppression) { "typecheck_bool_condition", "unexpected_friend", "warn_alloca")); clang::DiagnosticOptions DiagOpts; - clang::DiagnosticsEngine DiagEngine(new DiagnosticIDs, DiagOpts, + clang::DiagnosticsEngine DiagEngine(DiagnosticIDs::create(), DiagOpts, new clang::IgnoringDiagConsumer); using Diag = clang::Diagnostic; diff --git a/clang-tools-extra/clangd/unittests/FindSymbolsTests.cpp b/clang-tools-extra/clangd/unittests/FindSymbolsTests.cpp index 282859c..5b1630e 100644 --- a/clang-tools-extra/clangd/unittests/FindSymbolsTests.cpp +++ b/clang-tools-extra/clangd/unittests/FindSymbolsTests.cpp @@ -335,6 +335,7 @@ TEST(DocumentSymbols, BasicSymbols) { Foo(int a) {} void $decl[[f]](); friend void f1(); + friend void f2() {} friend class Friend; Foo& operator=(const Foo&); ~Foo(); @@ -346,7 +347,7 @@ TEST(DocumentSymbols, BasicSymbols) { }; void f1(); - inline void f2() {} + void f2(); static const int KInt = 2; const char* kStr = "123"; @@ -386,6 +387,8 @@ TEST(DocumentSymbols, BasicSymbols) { withDetail("(int)"), children()), AllOf(withName("f"), withKind(SymbolKind::Method), withDetail("void ()"), children()), + AllOf(withName("f2"), withKind(SymbolKind::Function), + withDetail("void ()"), children()), AllOf(withName("operator="), withKind(SymbolKind::Method), withDetail("Foo &(const Foo &)"), children()), AllOf(withName("~Foo"), withKind(SymbolKind::Constructor), diff --git a/clang-tools-extra/clangd/unittests/HoverTests.cpp b/clang-tools-extra/clangd/unittests/HoverTests.cpp index 4a21daf..12d260d 100644 --- a/clang-tools-extra/clangd/unittests/HoverTests.cpp +++ b/clang-tools-extra/clangd/unittests/HoverTests.cpp @@ -10,6 +10,7 @@ #include "Annotations.h" #include "Config.h" #include "Hover.h" +#include "Protocol.h" #include "TestFS.h" #include "TestIndex.h" #include "TestTU.h" @@ -3125,7 +3126,7 @@ TEST(Hover, All) { Expected.SymRange = T.range(); Case.ExpectedBuilder(Expected); - SCOPED_TRACE(H->present().asPlainText()); + SCOPED_TRACE(H->present(MarkupKind::PlainText)); EXPECT_EQ(H->NamespaceScope, Expected.NamespaceScope); EXPECT_EQ(H->LocalScope, Expected.LocalScope); EXPECT_EQ(H->Name, Expected.Name); @@ -3217,7 +3218,7 @@ TEST(Hover, Providers) { ASSERT_TRUE(H); HoverInfo Expected; Case.ExpectedBuilder(Expected); - SCOPED_TRACE(H->present().asMarkdown()); + SCOPED_TRACE(H->present(MarkupKind::Markdown)); EXPECT_EQ(H->Provider, Expected.Provider); } } @@ -3233,11 +3234,11 @@ TEST(Hover, ParseProviderInfo) { struct Case { HoverInfo HI; llvm::StringRef ExpectedMarkdown; - } Cases[] = {{HIFoo, "### `foo` \nprovided by `\"foo.h\"`"}, - {HIFooBar, "### `foo` \nprovided by `<bar.h>`"}}; + } Cases[] = {{HIFoo, "### `foo`\n\nprovided by `\"foo.h\"`"}, + {HIFooBar, "### `foo`\n\nprovided by `<bar.h>`"}}; for (const auto &Case : Cases) - EXPECT_EQ(Case.HI.present().asMarkdown(), Case.ExpectedMarkdown); + EXPECT_EQ(Case.HI.present(MarkupKind::Markdown), Case.ExpectedMarkdown); } TEST(Hover, UsedSymbols) { @@ -3287,7 +3288,7 @@ TEST(Hover, UsedSymbols) { ASSERT_TRUE(H); HoverInfo Expected; Case.ExpectedBuilder(Expected); - SCOPED_TRACE(H->present().asMarkdown()); + SCOPED_TRACE(H->present(MarkupKind::Markdown)); EXPECT_EQ(H->UsedSymbolNames, Expected.UsedSymbolNames); } } @@ -3441,6 +3442,7 @@ TEST(Hover, Present) { R"(class foo Size: 10 bytes + documentation template <typename T, typename C = bool> class Foo {})", @@ -3465,8 +3467,8 @@ template <typename T, typename C = bool> class Foo {})", }, "function foo\n" "\n" - "→ ret_type (aka can_ret_type)\n" - "Parameters:\n" + "→ ret_type (aka can_ret_type)\n\n" + "Parameters:\n\n" "- \n" "- type (aka can_type)\n" "- type foo (aka can_type)\n" @@ -3491,8 +3493,11 @@ template <typename T, typename C = bool> class Foo {})", R"(field foo Type: type (aka can_type) + Value = value + Offset: 12 bytes + Size: 4 bytes (+4 bytes padding), alignment 4 bytes // In test::Bar @@ -3514,8 +3519,11 @@ def)", R"(field foo Type: type (aka can_type) + Value = value + Offset: 4 bytes and 3 bits + Size: 25 bits (+4 bits padding), alignment 8 bytes // In test::Bar @@ -3573,6 +3581,7 @@ protected: size_t method())", R"(constructor cls Parameters: + - int a - int b = 5 @@ -3609,7 +3618,9 @@ private: union foo {})", R"(variable foo Type: int + Value = 3 + Passed as arg_a // In test::Bar @@ -3644,7 +3655,9 @@ Passed by value)", R"(variable foo Type: int + Value = 3 + Passed by reference as arg_a // In test::Bar @@ -3667,7 +3680,9 @@ int foo = 3)", R"(variable foo Type: int + Value = 3 + Passed as arg_a (converted to alias_int) // In test::Bar @@ -3705,7 +3720,9 @@ int foo = 3)", R"(variable foo Type: int + Value = 3 + Passed by const reference as arg_a (converted to int) // In test::Bar @@ -3741,83 +3758,140 @@ provides Foo, Bar, Baz, Foobar, Qux and 1 more)"}}; Config Cfg; Cfg.Hover.ShowAKA = true; WithContextValue WithCfg(Config::Key, std::move(Cfg)); - EXPECT_EQ(HI.present().asPlainText(), C.ExpectedRender); + EXPECT_EQ(HI.present(MarkupKind::PlainText), C.ExpectedRender); } } TEST(Hover, ParseDocumentation) { struct Case { llvm::StringRef Documentation; + llvm::StringRef ExpectedRenderEscapedMarkdown; llvm::StringRef ExpectedRenderMarkdown; llvm::StringRef ExpectedRenderPlainText; } Cases[] = {{ " \n foo\nbar", - "foo bar", + "foo\nbar", + "foo\nbar", "foo bar", }, { "foo\nbar \n ", - "foo bar", + "foo\nbar", + "foo\nbar", "foo bar", }, { "foo \nbar", - "foo bar", - "foo bar", + "foo \nbar", + "foo \nbar", + "foo\nbar", }, { "foo \nbar", - "foo bar", - "foo bar", + "foo \nbar", + "foo \nbar", + "foo\nbar", }, { "foo\n\n\nbar", - "foo \nbar", - "foo\nbar", + "foo\n\nbar", + "foo\n\nbar", + "foo\n\nbar", }, { "foo\n\n\n\tbar", - "foo \nbar", - "foo\nbar", + "foo\n\n\tbar", + "foo\n\n\tbar", + "foo\n\nbar", + }, + { + "foo\n\n\n bar", + "foo\n\n bar", + "foo\n\n bar", + "foo\n\nbar", + }, + { + "foo\n\n\n bar", + "foo\n\n bar", + "foo\n\n bar", + "foo\n\nbar", }, { "foo\n\n\n bar", - "foo \nbar", - "foo\nbar", + "foo\n\n bar", + "foo\n\n bar", + "foo\n\nbar", + }, + { + "foo\n\n\n\nbar", + "foo\n\nbar", + "foo\n\nbar", + "foo\n\nbar", + }, + { + "foo\n\n\n\n\tbar", + "foo\n\n\tbar", + "foo\n\n\tbar", + "foo\n\nbar", + }, + { + "foo\n\n\n\n bar", + "foo\n\n bar", + "foo\n\n bar", + "foo\n\nbar", + }, + { + "foo\n\n\n\n bar", + "foo\n\n bar", + "foo\n\n bar", + "foo\n\nbar", + }, + { + "foo\n\n\n\n bar", + "foo\n\n bar", + "foo\n\n bar", + "foo\n\nbar", }, { "foo.\nbar", - "foo. \nbar", + "foo.\nbar", + "foo.\nbar", "foo.\nbar", }, { "foo. \nbar", - "foo. \nbar", + "foo. \nbar", + "foo. \nbar", "foo.\nbar", }, { "foo\n*bar", - "foo \n\\*bar", + "foo\n\\*bar", + "foo\n*bar", "foo\n*bar", }, { "foo\nbar", - "foo bar", + "foo\nbar", + "foo\nbar", "foo bar", }, { "Tests primality of `p`.", "Tests primality of `p`.", "Tests primality of `p`.", + "Tests primality of `p`.", }, { "'`' should not occur in `Code`", "'\\`' should not occur in `Code`", "'`' should not occur in `Code`", + "'`' should not occur in `Code`", }, { "`not\nparsed`", - "\\`not parsed\\`", + "\\`not\nparsed\\`", + "`not\nparsed`", "`not parsed`", }}; @@ -3825,6 +3899,7 @@ TEST(Hover, ParseDocumentation) { markup::Document Output; parseDocumentation(C.Documentation, Output); + EXPECT_EQ(Output.asEscapedMarkdown(), C.ExpectedRenderEscapedMarkdown); EXPECT_EQ(Output.asMarkdown(), C.ExpectedRenderMarkdown); EXPECT_EQ(Output.asPlainText(), C.ExpectedRenderPlainText); } @@ -3837,7 +3912,7 @@ TEST(Hover, PresentHeadings) { HI.Kind = index::SymbolKind::Variable; HI.Name = "foo"; - EXPECT_EQ(HI.present().asMarkdown(), "### variable `foo`"); + EXPECT_EQ(HI.present(MarkupKind::Markdown), "### variable `foo`"); } // This is a separate test as rulers behave differently in markdown vs @@ -3850,23 +3925,23 @@ TEST(Hover, PresentRulers) { HI.Definition = "def"; llvm::StringRef ExpectedMarkdown = // - "### variable `foo` \n" + "### variable `foo`\n" "\n" "---\n" - "Value = `val` \n" + "Value = `val`\n" "\n" "---\n" "```cpp\n" "def\n" "```"; - EXPECT_EQ(HI.present().asMarkdown(), ExpectedMarkdown); + EXPECT_EQ(HI.present(MarkupKind::Markdown), ExpectedMarkdown); llvm::StringRef ExpectedPlaintext = R"pt(variable foo Value = val def)pt"; - EXPECT_EQ(HI.present().asPlainText(), ExpectedPlaintext); + EXPECT_EQ(HI.present(MarkupKind::PlainText), ExpectedPlaintext); } TEST(Hover, SpaceshipTemplateNoCrash) { diff --git a/clang-tools-extra/clangd/unittests/support/MarkupTests.cpp b/clang-tools-extra/clangd/unittests/support/MarkupTests.cpp index 2d86c91..482f230 100644 --- a/clang-tools-extra/clangd/unittests/support/MarkupTests.cpp +++ b/clang-tools-extra/clangd/unittests/support/MarkupTests.cpp @@ -17,6 +17,10 @@ namespace markup { namespace { std::string escape(llvm::StringRef Text) { + return Paragraph().appendText(Text.str()).asEscapedMarkdown(); +} + +std::string dontEscape(llvm::StringRef Text) { return Paragraph().appendText(Text.str()).asMarkdown(); } @@ -107,18 +111,135 @@ TEST(Render, Escaping) { // In code blocks we don't need to escape ASCII punctuation. Paragraph P = Paragraph(); P.appendCode("* foo !+ bar * baz"); - EXPECT_EQ(P.asMarkdown(), "`* foo !+ bar * baz`"); + EXPECT_EQ(P.asEscapedMarkdown(), "`* foo !+ bar * baz`"); // But we have to escape the backticks. P = Paragraph(); P.appendCode("foo`bar`baz", /*Preserve=*/true); - EXPECT_EQ(P.asMarkdown(), "`foo``bar``baz`"); + EXPECT_EQ(P.asEscapedMarkdown(), "`foo``bar``baz`"); // In plain-text, we fall back to different quotes. EXPECT_EQ(P.asPlainText(), "'foo`bar`baz'"); // Inline code blocks starting or ending with backticks should add spaces. P = Paragraph(); P.appendCode("`foo"); + EXPECT_EQ(P.asEscapedMarkdown(), "` ``foo `"); + P = Paragraph(); + P.appendCode("foo`"); + EXPECT_EQ(P.asEscapedMarkdown(), "` foo`` `"); + P = Paragraph(); + P.appendCode("`foo`"); + EXPECT_EQ(P.asEscapedMarkdown(), "` ``foo`` `"); + + // Code blocks might need more than 3 backticks. + Document D; + D.addCodeBlock("foobarbaz `\nqux"); + EXPECT_EQ(D.asEscapedMarkdown(), "```cpp\n" + "foobarbaz `\nqux\n" + "```"); + D = Document(); + D.addCodeBlock("foobarbaz ``\nqux"); + EXPECT_THAT(D.asEscapedMarkdown(), "```cpp\n" + "foobarbaz ``\nqux\n" + "```"); + D = Document(); + D.addCodeBlock("foobarbaz ```\nqux"); + EXPECT_EQ(D.asEscapedMarkdown(), "````cpp\n" + "foobarbaz ```\nqux\n" + "````"); + D = Document(); + D.addCodeBlock("foobarbaz ` `` ``` ```` `\nqux"); + EXPECT_EQ(D.asEscapedMarkdown(), "`````cpp\n" + "foobarbaz ` `` ``` ```` `\nqux\n" + "`````"); +} + +TEST(Render, NoEscaping) { + // Check all ASCII punctuation. + std::string Punctuation = R"txt(!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~)txt"; + EXPECT_EQ(dontEscape(Punctuation), Punctuation); + + // Inline code + EXPECT_THAT(dontEscape("`foo`"), escapedNone()); + EXPECT_THAT(dontEscape("`foo"), escapedNone()); + EXPECT_THAT(dontEscape("foo`"), escapedNone()); + EXPECT_THAT(dontEscape("``foo``"), escapedNone()); + // Code blocks + EXPECT_THAT(dontEscape("```"), escapedNone()); + EXPECT_THAT(dontEscape("~~~"), escapedNone()); + + // Rulers and headings + EXPECT_THAT(dontEscape("## Heading"), escapedNone()); + EXPECT_THAT(dontEscape("Foo # bar"), escapedNone()); + EXPECT_THAT(dontEscape("---"), escapedNone()); + EXPECT_THAT(dontEscape("-"), escapedNone()); + EXPECT_THAT(dontEscape("==="), escapedNone()); + EXPECT_THAT(dontEscape("="), escapedNone()); + EXPECT_THAT(dontEscape("***"), escapedNone()); // \** could start emphasis! + + // HTML tags. + EXPECT_THAT(dontEscape("<pre"), escaped('<')); + EXPECT_THAT(dontEscape("< pre"), escapedNone()); + EXPECT_THAT(dontEscape("if a<b then"), escaped('<')); + EXPECT_THAT(dontEscape("if a<b then c."), escapedNone()); + EXPECT_THAT(dontEscape("if a<b then c='foo'."), escaped('<')); + EXPECT_THAT(dontEscape("std::vector<T>"), escaped('<')); + EXPECT_THAT(dontEscape("std::vector<std::string>"), escaped('<')); + EXPECT_THAT(dontEscape("std::map<int, int>"), escapedNone()); + // Autolinks + EXPECT_THAT(dontEscape("Email <foo@bar.com>"), escapedNone()); + EXPECT_THAT(dontEscape("Website <http://foo.bar>"), escapedNone()); + + // Bullet lists. + EXPECT_THAT(dontEscape("- foo"), escapedNone()); + EXPECT_THAT(dontEscape("* foo"), escapedNone()); + EXPECT_THAT(dontEscape("+ foo"), escapedNone()); + EXPECT_THAT(dontEscape("+"), escapedNone()); + EXPECT_THAT(dontEscape("a + foo"), escapedNone()); + EXPECT_THAT(dontEscape("a+ foo"), escapedNone()); + EXPECT_THAT(dontEscape("1. foo"), escapedNone()); + EXPECT_THAT(dontEscape("a. foo"), escapedNone()); + + // Emphasis. + EXPECT_THAT(dontEscape("*foo*"), escapedNone()); + EXPECT_THAT(dontEscape("**foo**"), escapedNone()); + EXPECT_THAT(dontEscape("*foo"), escapedNone()); + EXPECT_THAT(dontEscape("foo *"), escapedNone()); + EXPECT_THAT(dontEscape("foo * bar"), escapedNone()); + EXPECT_THAT(dontEscape("foo_bar"), escapedNone()); + EXPECT_THAT(dontEscape("foo _bar"), escapedNone()); + EXPECT_THAT(dontEscape("foo_ bar"), escapedNone()); + EXPECT_THAT(dontEscape("foo _ bar"), escapedNone()); + + // HTML entities. + EXPECT_THAT(dontEscape("fish &chips;"), escaped('&')); + EXPECT_THAT(dontEscape("fish & chips;"), escapedNone()); + EXPECT_THAT(dontEscape("fish &chips"), escapedNone()); + EXPECT_THAT(dontEscape("foo * bar"), escaped('&')); + EXPECT_THAT(dontEscape("foo ¯ bar"), escaped('&')); + EXPECT_THAT(dontEscape("foo &?; bar"), escapedNone()); + + // Links. + EXPECT_THAT(dontEscape("[foo](bar)"), escapedNone()); + EXPECT_THAT(dontEscape("[foo]: bar"), escapedNone()); + // No need to escape these, as the target never exists. + EXPECT_THAT(dontEscape("[foo][]"), escapedNone()); + EXPECT_THAT(dontEscape("[foo][bar]"), escapedNone()); + EXPECT_THAT(dontEscape("[foo]"), escapedNone()); + + // In code blocks we don't need to escape ASCII punctuation. + Paragraph P = Paragraph(); + P.appendCode("* foo !+ bar * baz"); + EXPECT_EQ(P.asMarkdown(), "`* foo !+ bar * baz`"); + + // But we have to escape the backticks. + P = Paragraph(); + P.appendCode("foo`bar`baz", /*Preserve=*/true); + EXPECT_EQ(P.asMarkdown(), "`foo``bar``baz`"); + + // Inline code blocks starting or ending with backticks should add spaces. + P = Paragraph(); + P.appendCode("`foo"); EXPECT_EQ(P.asMarkdown(), "` ``foo `"); P = Paragraph(); P.appendCode("foo`"); @@ -150,17 +271,6 @@ TEST(Render, Escaping) { "`````"); } -TEST(Paragraph, Chunks) { - Paragraph P = Paragraph(); - P.appendText("One "); - P.appendCode("fish"); - P.appendText(", two "); - P.appendCode("fish", /*Preserve=*/true); - - EXPECT_EQ(P.asMarkdown(), "One `fish`, two `fish`"); - EXPECT_EQ(P.asPlainText(), "One fish, two `fish`"); -} - TEST(Paragraph, SeparationOfChunks) { // This test keeps appending contents to a single Paragraph and checks // expected accumulated contents after each one. @@ -168,28 +278,122 @@ TEST(Paragraph, SeparationOfChunks) { Paragraph P; P.appendText("after "); + EXPECT_EQ(P.asEscapedMarkdown(), "after"); EXPECT_EQ(P.asMarkdown(), "after"); EXPECT_EQ(P.asPlainText(), "after"); P.appendCode("foobar").appendSpace(); + EXPECT_EQ(P.asEscapedMarkdown(), "after `foobar`"); EXPECT_EQ(P.asMarkdown(), "after `foobar`"); EXPECT_EQ(P.asPlainText(), "after foobar"); P.appendText("bat"); + EXPECT_EQ(P.asEscapedMarkdown(), "after `foobar` bat"); EXPECT_EQ(P.asMarkdown(), "after `foobar` bat"); EXPECT_EQ(P.asPlainText(), "after foobar bat"); P.appendCode("no").appendCode("space"); + EXPECT_EQ(P.asEscapedMarkdown(), "after `foobar` bat`no` `space`"); EXPECT_EQ(P.asMarkdown(), "after `foobar` bat`no` `space`"); EXPECT_EQ(P.asPlainText(), "after foobar batno space"); + + P.appendText(" text"); + EXPECT_EQ(P.asEscapedMarkdown(), "after `foobar` bat`no` `space` text"); + EXPECT_EQ(P.asMarkdown(), "after `foobar` bat`no` `space` text"); + EXPECT_EQ(P.asPlainText(), "after foobar batno space text"); + + P.appendSpace().appendCode("code").appendText(".\n newline"); + EXPECT_EQ(P.asEscapedMarkdown(), + "after `foobar` bat`no` `space` text `code`.\n newline"); + EXPECT_EQ(P.asMarkdown(), + "after `foobar` bat`no` `space` text `code`.\n newline"); + EXPECT_EQ(P.asPlainText(), "after foobar batno space text code.\nnewline"); +} + +TEST(Paragraph, SeparationOfChunks2) { + // This test keeps appending contents to a single Paragraph and checks + // expected accumulated contents after each one. + // Purpose is to check for separation between different chunks + // where the spacing is in the appended string rather set by appendSpace. + Paragraph P; + + P.appendText("after "); + EXPECT_EQ(P.asEscapedMarkdown(), "after"); + EXPECT_EQ(P.asMarkdown(), "after"); + EXPECT_EQ(P.asPlainText(), "after"); + + P.appendText("foobar"); + EXPECT_EQ(P.asEscapedMarkdown(), "after foobar"); + EXPECT_EQ(P.asMarkdown(), "after foobar"); + EXPECT_EQ(P.asPlainText(), "after foobar"); + + P.appendText(" bat"); + EXPECT_EQ(P.asEscapedMarkdown(), "after foobar bat"); + EXPECT_EQ(P.asMarkdown(), "after foobar bat"); + EXPECT_EQ(P.asPlainText(), "after foobar bat"); + + P.appendText("baz"); + EXPECT_EQ(P.asEscapedMarkdown(), "after foobar batbaz"); + EXPECT_EQ(P.asMarkdown(), "after foobar batbaz"); + EXPECT_EQ(P.asPlainText(), "after foobar batbaz"); + + P.appendText(" faz "); + EXPECT_EQ(P.asEscapedMarkdown(), "after foobar batbaz faz"); + EXPECT_EQ(P.asMarkdown(), "after foobar batbaz faz"); + EXPECT_EQ(P.asPlainText(), "after foobar batbaz faz"); + + P.appendText(" bar "); + EXPECT_EQ(P.asEscapedMarkdown(), "after foobar batbaz faz bar"); + EXPECT_EQ(P.asMarkdown(), "after foobar batbaz faz bar"); + EXPECT_EQ(P.asPlainText(), "after foobar batbaz faz bar"); + + P.appendText("qux"); + EXPECT_EQ(P.asEscapedMarkdown(), "after foobar batbaz faz bar qux"); + EXPECT_EQ(P.asMarkdown(), "after foobar batbaz faz bar qux"); + EXPECT_EQ(P.asPlainText(), "after foobar batbaz faz bar qux"); +} + +TEST(Paragraph, SeparationOfChunks3) { + // This test keeps appending contents to a single Paragraph and checks + // expected accumulated contents after each one. + // Purpose is to check for separation between different chunks + // where the spacing is in the appended string rather set by appendSpace. + Paragraph P; + + P.appendText("after \n"); + EXPECT_EQ(P.asEscapedMarkdown(), "after"); + EXPECT_EQ(P.asMarkdown(), "after"); + EXPECT_EQ(P.asPlainText(), "after"); + + P.appendText(" foobar\n"); + EXPECT_EQ(P.asEscapedMarkdown(), "after \n foobar"); + EXPECT_EQ(P.asMarkdown(), "after \n foobar"); + EXPECT_EQ(P.asPlainText(), "after\nfoobar"); + + P.appendText("- bat\n"); + EXPECT_EQ(P.asEscapedMarkdown(), "after \n foobar\n\\- bat"); + EXPECT_EQ(P.asMarkdown(), "after \n foobar\n- bat"); + EXPECT_EQ(P.asPlainText(), "after\nfoobar\n- bat"); + + P.appendText("- baz"); + EXPECT_EQ(P.asEscapedMarkdown(), "after \n foobar\n\\- bat\n\\- baz"); + EXPECT_EQ(P.asMarkdown(), "after \n foobar\n- bat\n- baz"); + EXPECT_EQ(P.asPlainText(), "after\nfoobar\n- bat\n- baz"); + + P.appendText(" faz "); + EXPECT_EQ(P.asEscapedMarkdown(), "after \n foobar\n\\- bat\n\\- baz faz"); + EXPECT_EQ(P.asMarkdown(), "after \n foobar\n- bat\n- baz faz"); + EXPECT_EQ(P.asPlainText(), "after\nfoobar\n- bat\n- baz faz"); } TEST(Paragraph, ExtraSpaces) { - // Make sure spaces inside chunks are dropped. + // Make sure spaces inside chunks are preserved for markdown + // and dropped for plain text. Paragraph P; P.appendText("foo\n \t baz"); P.appendCode(" bar\n"); - EXPECT_EQ(P.asMarkdown(), "foo baz`bar`"); + EXPECT_EQ(P.asEscapedMarkdown(), "foo\n \t baz`bar`"); + EXPECT_EQ(P.asMarkdown(), "foo\n \t baz`bar`"); EXPECT_EQ(P.asPlainText(), "foo bazbar"); } @@ -197,7 +401,8 @@ TEST(Paragraph, SpacesCollapsed) { Paragraph P; P.appendText(" foo bar "); P.appendText(" baz "); - EXPECT_EQ(P.asMarkdown(), "foo bar baz"); + EXPECT_EQ(P.asEscapedMarkdown(), "foo bar baz"); + EXPECT_EQ(P.asMarkdown(), "foo bar baz"); EXPECT_EQ(P.asPlainText(), "foo bar baz"); } @@ -206,21 +411,60 @@ TEST(Paragraph, NewLines) { Paragraph P; P.appendText(" \n foo\nbar\n "); P.appendCode(" \n foo\nbar \n "); - EXPECT_EQ(P.asMarkdown(), "foo bar `foo bar`"); + EXPECT_EQ(P.asEscapedMarkdown(), "foo\nbar\n `foo bar`"); + EXPECT_EQ(P.asMarkdown(), "foo\nbar\n `foo bar`"); EXPECT_EQ(P.asPlainText(), "foo bar foo bar"); } +TEST(Paragraph, BoldText) { + Paragraph P; + P.appendBoldText(""); + EXPECT_EQ(P.asEscapedMarkdown(), ""); + EXPECT_EQ(P.asMarkdown(), ""); + EXPECT_EQ(P.asPlainText(), ""); + + P.appendBoldText(" \n foo\nbar\n "); + EXPECT_EQ(P.asEscapedMarkdown(), "\\*\\*foo bar\\*\\*"); + EXPECT_EQ(P.asMarkdown(), "**foo bar**"); + EXPECT_EQ(P.asPlainText(), "**foo bar**"); + + P.appendSpace().appendBoldText("foobar"); + EXPECT_EQ(P.asEscapedMarkdown(), "\\*\\*foo bar\\*\\* \\*\\*foobar\\*\\*"); + EXPECT_EQ(P.asMarkdown(), "**foo bar** **foobar**"); + EXPECT_EQ(P.asPlainText(), "**foo bar** **foobar**"); +} + +TEST(Paragraph, EmphasizedText) { + Paragraph P; + P.appendEmphasizedText(""); + EXPECT_EQ(P.asEscapedMarkdown(), ""); + EXPECT_EQ(P.asMarkdown(), ""); + EXPECT_EQ(P.asPlainText(), ""); + + P.appendEmphasizedText(" \n foo\nbar\n "); + EXPECT_EQ(P.asEscapedMarkdown(), "\\*foo bar\\*"); + EXPECT_EQ(P.asMarkdown(), "*foo bar*"); + EXPECT_EQ(P.asPlainText(), "*foo bar*"); + + P.appendSpace().appendEmphasizedText("foobar"); + EXPECT_EQ(P.asEscapedMarkdown(), "\\*foo bar\\* \\*foobar\\*"); + EXPECT_EQ(P.asMarkdown(), "*foo bar* *foobar*"); + EXPECT_EQ(P.asPlainText(), "*foo bar* *foobar*"); +} + TEST(Document, Separators) { Document D; D.addParagraph().appendText("foo"); D.addCodeBlock("test"); D.addParagraph().appendText("bar"); - const char ExpectedMarkdown[] = R"md(foo + const char ExpectedMarkdown[] = R"md(foo + ```cpp test ``` bar)md"; + EXPECT_EQ(D.asEscapedMarkdown(), ExpectedMarkdown); EXPECT_EQ(D.asMarkdown(), ExpectedMarkdown); const char ExpectedText[] = R"pt(foo @@ -238,7 +482,8 @@ TEST(Document, Ruler) { // Ruler followed by paragraph. D.addParagraph().appendText("bar"); - EXPECT_EQ(D.asMarkdown(), "foo \n\n---\nbar"); + EXPECT_EQ(D.asEscapedMarkdown(), "foo\n\n---\nbar"); + EXPECT_EQ(D.asMarkdown(), "foo\n\n---\nbar"); EXPECT_EQ(D.asPlainText(), "foo\n\nbar"); D = Document(); @@ -246,7 +491,8 @@ TEST(Document, Ruler) { D.addRuler(); D.addCodeBlock("bar"); // Ruler followed by a codeblock. - EXPECT_EQ(D.asMarkdown(), "foo \n\n---\n```cpp\nbar\n```"); + EXPECT_EQ(D.asEscapedMarkdown(), "foo\n\n---\n```cpp\nbar\n```"); + EXPECT_EQ(D.asMarkdown(), "foo\n\n---\n```cpp\nbar\n```"); EXPECT_EQ(D.asPlainText(), "foo\n\nbar"); // Ruler followed by another ruler @@ -254,13 +500,15 @@ TEST(Document, Ruler) { D.addParagraph().appendText("foo"); D.addRuler(); D.addRuler(); + EXPECT_EQ(D.asEscapedMarkdown(), "foo"); EXPECT_EQ(D.asMarkdown(), "foo"); EXPECT_EQ(D.asPlainText(), "foo"); // Multiple rulers between blocks D.addRuler(); D.addParagraph().appendText("foo"); - EXPECT_EQ(D.asMarkdown(), "foo \n\n---\nfoo"); + EXPECT_EQ(D.asEscapedMarkdown(), "foo\n\n---\nfoo"); + EXPECT_EQ(D.asMarkdown(), "foo\n\n---\nfoo"); EXPECT_EQ(D.asPlainText(), "foo\n\nfoo"); } @@ -272,7 +520,8 @@ TEST(Document, Append) { E.addRuler(); E.addParagraph().appendText("bar"); D.append(std::move(E)); - EXPECT_EQ(D.asMarkdown(), "foo \n\n---\nbar"); + EXPECT_EQ(D.asEscapedMarkdown(), "foo\n\n---\nbar"); + EXPECT_EQ(D.asMarkdown(), "foo\n\n---\nbar"); } TEST(Document, Heading) { @@ -280,8 +529,9 @@ TEST(Document, Heading) { D.addHeading(1).appendText("foo"); D.addHeading(2).appendText("bar"); D.addParagraph().appendText("baz"); - EXPECT_EQ(D.asMarkdown(), "# foo \n## bar \nbaz"); - EXPECT_EQ(D.asPlainText(), "foo\nbar\nbaz"); + EXPECT_EQ(D.asEscapedMarkdown(), "# foo\n\n## bar\n\nbaz"); + EXPECT_EQ(D.asMarkdown(), "# foo\n\n## bar\n\nbaz"); + EXPECT_EQ(D.asPlainText(), "foo\n\nbar\n\nbaz"); } TEST(CodeBlock, Render) { @@ -299,6 +549,7 @@ foo R"pt(foo bar baz)pt"; + EXPECT_EQ(D.asEscapedMarkdown(), ExpectedMarkdown); EXPECT_EQ(D.asMarkdown(), ExpectedMarkdown); EXPECT_EQ(D.asPlainText(), ExpectedPlainText); D.addCodeBlock("foo"); @@ -311,6 +562,7 @@ foo ```cpp foo ```)md"; + EXPECT_EQ(D.asEscapedMarkdown(), ExpectedMarkdown); EXPECT_EQ(D.asMarkdown(), ExpectedMarkdown); ExpectedPlainText = R"pt(foo @@ -325,18 +577,20 @@ TEST(BulletList, Render) { BulletList L; // Flat list L.addItem().addParagraph().appendText("foo"); + EXPECT_EQ(L.asEscapedMarkdown(), "- foo"); EXPECT_EQ(L.asMarkdown(), "- foo"); EXPECT_EQ(L.asPlainText(), "- foo"); L.addItem().addParagraph().appendText("bar"); llvm::StringRef Expected = R"md(- foo - bar)md"; + EXPECT_EQ(L.asEscapedMarkdown(), Expected); EXPECT_EQ(L.asMarkdown(), Expected); EXPECT_EQ(L.asPlainText(), Expected); // Nested list, with a single item. Document &D = L.addItem(); - // First item with foo\nbaz + // First item with 2 paragraphs - foo\n\n baz D.addParagraph().appendText("foo"); D.addParagraph().appendText("baz"); @@ -352,18 +606,27 @@ TEST(BulletList, Render) { DeepDoc.addParagraph().appendText("baz"); StringRef ExpectedMarkdown = R"md(- foo - bar -- foo - baz - - foo - - baz +- foo + + baz + + - foo + + - baz + baz)md"; + EXPECT_EQ(L.asEscapedMarkdown(), ExpectedMarkdown); EXPECT_EQ(L.asMarkdown(), ExpectedMarkdown); StringRef ExpectedPlainText = R"pt(- foo - bar - foo + baz + - foo + - baz + baz)pt"; EXPECT_EQ(L.asPlainText(), ExpectedPlainText); @@ -371,21 +634,31 @@ TEST(BulletList, Render) { Inner.addParagraph().appendText("after"); ExpectedMarkdown = R"md(- foo - bar -- foo - baz - - foo - - baz +- foo + + baz + + - foo + + - baz + baz - + after)md"; + EXPECT_EQ(L.asEscapedMarkdown(), ExpectedMarkdown); EXPECT_EQ(L.asMarkdown(), ExpectedMarkdown); ExpectedPlainText = R"pt(- foo - bar - foo + baz + - foo + - baz + baz + after)pt"; EXPECT_EQ(L.asPlainText(), ExpectedPlainText); } diff --git a/clang-tools-extra/clangd/unittests/tweaks/TweakTests.cpp b/clang-tools-extra/clangd/unittests/tweaks/TweakTests.cpp index e39b702..b6607e9 100644 --- a/clang-tools-extra/clangd/unittests/tweaks/TweakTests.cpp +++ b/clang-tools-extra/clangd/unittests/tweaks/TweakTests.cpp @@ -45,7 +45,7 @@ TEST(FileEdits, AbsolutePath) { MemFS->addFile(Path, 0, llvm::MemoryBuffer::getMemBuffer("", Path)); FileManager FM(FileSystemOptions(), MemFS); DiagnosticOptions DiagOpts; - DiagnosticsEngine DE(new DiagnosticIDs, DiagOpts); + DiagnosticsEngine DE(DiagnosticIDs::create(), DiagOpts); SourceManager SM(DE, FM); for (const auto *Path : RelPaths) { diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index bccb0ca..e45f870 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -101,9 +101,25 @@ Improvements to clang-query Improvements to clang-tidy -------------------------- +- The :program:`run-clang-tidy.py` and :program:`clang-tidy-diff.py` scripts + now run checks in parallel by default using all available hardware threads. + Both scripts display the number of threads being used in their output. + New checks ^^^^^^^^^^ +- New :doc:`bugprone-invalid-enum-default-initialization + <clang-tidy/checks/bugprone/invalid-enum-default-initialization>` check. + + Detects default initialization (to 0) of variables with ``enum`` type where + the enum has no enumerator with value of 0. + +- New :doc:`llvm-mlir-op-builder + <clang-tidy/checks/llvm/use-new-mlir-op-builder>` check. + + Checks for uses of MLIR's old/to be deprecated ``OpBuilder::create<T>`` form + and suggests using ``T::create`` instead. + New check aliases ^^^^^^^^^^^^^^^^^ @@ -114,6 +130,40 @@ Changes in existing checks <clang-tidy/checks/bugprone/infinite-loop>` check by adding detection for variables introduced by structured bindings. +- Improved :doc:`bugprone-signed-char-misuse + <clang-tidy/checks/bugprone/signed-char-misuse>` check by fixing + false positives on C23 enums with the fixed underlying type of signed char. + +- Improved :doc:`bugprone-unhandled-self-assignment + <clang-tidy/checks/bugprone/unhandled-self-assignment>` check by adding + an additional matcher that generalizes the copy-and-swap idiom pattern + detection. + +- Improved :doc:`misc-header-include-cycle + <clang-tidy/checks/misc/header-include-cycle>` check performance. + +- Improved :doc:`modernize-use-designated-initializers + <clang-tidy/checks/modernize/use-designated-initializers>` check to + suggest using designated initializers for aliased aggregate types. + +- Improved :doc:`modernize-use-std-format + <clang-tidy/checks/modernize/use-std-format>` check to correctly match + when the format string is converted to a different type by an implicit + constructor call. + +- Improved :doc:`modernize-use-std-print + <clang-tidy/checks/modernize/use-std-print>` check to correctly match + when the format string is converted to a different type by an implicit + constructor call. + +- Improved :doc:`portability-template-virtual-member-function + <clang-tidy/checks/portability/template-virtual-member-function>` check to + avoid false positives on pure virtual member functions. + +- Improved :doc:`readability-qualified-auto + <clang-tidy/checks/readability/qualified-auto>` check by adding the option + `IgnoreAliasing`, that allows not looking at underlying types of type aliases. + Removed checks ^^^^^^^^^^^^^^ @@ -140,4 +190,3 @@ Improvements to pp-trace Clang-tidy Visual Studio plugin ------------------------------- - diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/invalid-enum-default-initialization.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/invalid-enum-default-initialization.rst new file mode 100644 index 0000000..a3bd2b6 --- /dev/null +++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/invalid-enum-default-initialization.rst @@ -0,0 +1,72 @@ +.. title:: clang-tidy - bugprone-invalid-enum-default-initialization + +bugprone-invalid-enum-default-initialization +============================================ + +Detects default initialization (to 0) of variables with ``enum`` type where +the enum has no enumerator with value of 0. + +In C++ a default initialization is performed if a variable is initialized with +initializer list or in other implicit ways, and no value is specified at the +initialization. In such cases the value 0 is used for the initialization. +This also applies to enumerations even if it does not have an enumerator with +value 0. In this way a variable with the ``enum`` type may contain initially an +invalid value (if the program expects that it contains only the listed +enumerator values). + +The check emits a warning only if an ``enum`` variable is default-initialized +(contrary to not initialized) and the ``enum`` does not have an enumerator with +value of 0. The type can be a scoped or non-scoped ``enum``. Unions are not +handled by the check (if it contains a member of enumeration type). + +.. code-block:: c++ + + enum class Enum1: int { + A = 1, + B + }; + + enum class Enum0: int { + A = 0, + B + }; + + void f() { + Enum1 X1{}; // warn: 'X1' is initialized to 0 + Enum1 X2 = Enum1(); // warn: 'X2' is initialized to 0 + Enum1 X3; // no warning: 'X3' is not initialized + Enum0 X4{}; // no warning: type has an enumerator with value of 0 + } + + struct S1 { + Enum1 A; + S(): A() {} // warn: 'A' is initialized to 0 + }; + + struct S2 { + int A; + Enum1 B; + }; + + S2 VarS2{}; // warn: member 'B' is initialized to 0 + +The check applies to initialization of arrays or structures with initialization +lists in C code too. In these cases elements not specified in the list (and have +enum type) are set to 0. + +.. code-block:: c + + enum Enum1 { + Enum1_A = 1, + Enum1_B + }; + struct Struct1 { + int a; + enum Enum1 b; + }; + + enum Enum1 Array1[2] = {Enum1_A}; // warn: omitted elements are initialized to 0 + enum Enum1 Array2[2][2] = {{Enum1_A}, {Enum1_A}}; // warn: last element of both nested arrays is initialized to 0 + enum Enum1 Array3[2][2] = {{Enum1_A, Enum1_A}}; // warn: elements of second array are initialized to 0 + + struct Struct1 S1 = {1}; // warn: element 'b' is initialized to 0 diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst index 0cffbd3..b6444eb 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/list.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -106,6 +106,7 @@ Clang-Tidy Checks :doc:`bugprone-incorrect-roundings <bugprone/incorrect-roundings>`, :doc:`bugprone-infinite-loop <bugprone/infinite-loop>`, :doc:`bugprone-integer-division <bugprone/integer-division>`, + :doc:`bugprone-invalid-enum-default-initialization <bugprone/invalid-enum-default-initialization>`, :doc:`bugprone-lambda-function-name <bugprone/lambda-function-name>`, :doc:`bugprone-macro-parentheses <bugprone/macro-parentheses>`, "Yes" :doc:`bugprone-macro-repeated-side-effects <bugprone/macro-repeated-side-effects>`, @@ -247,6 +248,7 @@ Clang-Tidy Checks :doc:`linuxkernel-must-check-errs <linuxkernel/must-check-errs>`, :doc:`llvm-header-guard <llvm/header-guard>`, :doc:`llvm-include-order <llvm/include-order>`, "Yes" + :doc:`llvm-use-new-mlir-op-builder <llvm/use-new-mlir-op-builder>`, "Yes" :doc:`llvm-namespace-comment <llvm/namespace-comment>`, :doc:`llvm-prefer-isa-or-dyn-cast-in-conditionals <llvm/prefer-isa-or-dyn-cast-in-conditionals>`, "Yes" :doc:`llvm-prefer-register-over-unsigned <llvm/prefer-register-over-unsigned>`, "Yes" diff --git a/clang-tools-extra/docs/clang-tidy/checks/llvm/use-new-mlir-op-builder.rst b/clang-tools-extra/docs/clang-tidy/checks/llvm/use-new-mlir-op-builder.rst new file mode 100644 index 0000000..dc1989d --- /dev/null +++ b/clang-tools-extra/docs/clang-tidy/checks/llvm/use-new-mlir-op-builder.rst @@ -0,0 +1,21 @@ +.. title:: clang-tidy - llvm-use-new-mlir-op-builder + +llvm-mlir-op-builder +==================== + +Checks for uses of MLIR's old/to be deprecated ``OpBuilder::create<T>`` form +and suggests using ``T::create`` instead. + +Example +------- + +.. code-block:: c++ + + builder.create<FooOp>(builder.getUnknownLoc(), "baz"); + + +Transforms to: + +.. code-block:: c++ + + FooOp::create(builder, builder.getUnknownLoc(), "baz"); diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/qualified-auto.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/qualified-auto.rst index efa0857..34390e2 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/readability/qualified-auto.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/readability/qualified-auto.rst @@ -96,3 +96,45 @@ Note in the LLVM alias, the default value is `false`. matched against only the type name (i.e. ``Type``). E.g. to suppress reports for ``std::array`` iterators use `std::array<.*>::(const_)?iterator` string. The default is an empty string. + +.. option:: IgnoreAliasing + + If set to `true` the check will use the underlying type to determine the type + that ``auto`` is deduced to. If set to `false` the check will not look beyond + the first type alias. + Default value is `true`. + + .. code-block:: c++ + + using IntPtr = int*; + IntPtr foo(); + + auto bar = foo(); + + If :option:`IgnoreAliasing` is set to `true`, it will be transformed into: + + .. code-block:: c++ + + auto *bar = foo(); + + Otherwise no changes will occur. + +Limitations +----------- + +When :option:`IgnoreAliasing` is set to `false`, there are cases where +Clang has not preserved the type alias and the underlying type will be used so +false positives may occur. + +For example: + +.. code-block:: c++ + + using IntPtr = int *; + + void loopPtr(const std::vector<IntPtr> &VectorIntPtr) { + + // May fail for IgnoreAliasing==false as AST does not have the 'IntPtr' + for (auto Data : VectorIntPtr) { + } + } diff --git a/clang-tools-extra/modularize/ModularizeUtilities.cpp b/clang-tools-extra/modularize/ModularizeUtilities.cpp index 8a24f21..4dd84fe 100644 --- a/clang-tools-extra/modularize/ModularizeUtilities.cpp +++ b/clang-tools-extra/modularize/ModularizeUtilities.cpp @@ -47,7 +47,7 @@ ModularizeUtilities::ModularizeUtilities(std::vector<std::string> &InputPaths, ProblemFilesPath(ProblemFilesListPath), HasModuleMap(false), MissingHeaderCount(0), // Init clang stuff needed for loading the module map and preprocessing. - LangOpts(new LangOptions()), DiagIDs(new DiagnosticIDs()), + LangOpts(new LangOptions()), DiagIDs(DiagnosticIDs::create()), DC(llvm::errs(), DiagnosticOpts), Diagnostics(new DiagnosticsEngine(DiagIDs, DiagnosticOpts, &DC, false)), TargetOpts(new ModuleMapTargetOptions()), diff --git a/clang-tools-extra/test/clang-apply-replacements/basic.cpp b/clang-tools-extra/test/clang-apply-replacements/basic.cpp index 4f19a96..2399307 100644 --- a/clang-tools-extra/test/clang-apply-replacements/basic.cpp +++ b/clang-tools-extra/test/clang-apply-replacements/basic.cpp @@ -1,17 +1,17 @@ -// RUN: mkdir -p %T/Inputs/basic -// RUN: grep -Ev "// *[A-Z-]+:" %S/Inputs/basic/basic.h > %T/Inputs/basic/basic.h -// RUN: sed "s#\$(path)#%/T/Inputs/basic#" %S/Inputs/basic/file1.yaml > %T/Inputs/basic/file1.yaml -// RUN: sed "s#\$(path)#%/T/Inputs/basic#" %S/Inputs/basic/file2.yaml > %T/Inputs/basic/file2.yaml -// RUN: clang-apply-replacements %T/Inputs/basic -// RUN: FileCheck -input-file=%T/Inputs/basic/basic.h %S/Inputs/basic/basic.h +// RUN: mkdir -p %t.dir/Inputs/basic +// RUN: grep -Ev "// *[A-Z-]+:" %S/Inputs/basic/basic.h > %t.dir/Inputs/basic/basic.h +// RUN: sed "s#\$(path)#%/t.dir/Inputs/basic#" %S/Inputs/basic/file1.yaml > %t.dir/Inputs/basic/file1.yaml +// RUN: sed "s#\$(path)#%/t.dir/Inputs/basic#" %S/Inputs/basic/file2.yaml > %t.dir/Inputs/basic/file2.yaml +// RUN: clang-apply-replacements %t.dir/Inputs/basic +// RUN: FileCheck -input-file=%t.dir/Inputs/basic/basic.h %S/Inputs/basic/basic.h // // Check that the yaml files are *not* deleted after running clang-apply-replacements without remove-change-desc-files. -// RUN: ls -1 %T/Inputs/basic | FileCheck %s --check-prefix=YAML +// RUN: ls -1 %t.dir/Inputs/basic | FileCheck %s --check-prefix=YAML // // Check that the yaml files *are* deleted after running clang-apply-replacements with remove-change-desc-files. -// RUN: grep -Ev "// *[A-Z-]+:" %S/Inputs/basic/basic.h > %T/Inputs/basic/basic.h -// RUN: clang-apply-replacements -remove-change-desc-files %T/Inputs/basic -// RUN: ls -1 %T/Inputs/basic | FileCheck %s --check-prefix=NO_YAML +// RUN: grep -Ev "// *[A-Z-]+:" %S/Inputs/basic/basic.h > %t.dir/Inputs/basic/basic.h +// RUN: clang-apply-replacements -remove-change-desc-files %t.dir/Inputs/basic +// RUN: ls -1 %t.dir/Inputs/basic | FileCheck %s --check-prefix=NO_YAML // // YAML: {{^file.\.yaml$}} // NO_YAML-NOT: {{^file.\.yaml$}} diff --git a/clang-tools-extra/test/clang-apply-replacements/conflict.cpp b/clang-tools-extra/test/clang-apply-replacements/conflict.cpp index c1f2342..7b0a8c2 100644 --- a/clang-tools-extra/test/clang-apply-replacements/conflict.cpp +++ b/clang-tools-extra/test/clang-apply-replacements/conflict.cpp @@ -1,17 +1,17 @@ -// RUN: mkdir -p %T/Inputs/conflict -// RUN: sed "s#\$(path)#%/S/Inputs/conflict#" %S/Inputs/conflict/file1.yaml > %T/Inputs/conflict/file1.yaml -// RUN: sed "s#\$(path)#%/S/Inputs/conflict#" %S/Inputs/conflict/file2.yaml > %T/Inputs/conflict/file2.yaml -// RUN: sed "s#\$(path)#%/S/Inputs/conflict#" %S/Inputs/conflict/file3.yaml > %T/Inputs/conflict/file3.yaml -// RUN: sed "s#\$(path)#%/S/Inputs/conflict#" %S/Inputs/conflict/expected.txt > %T/Inputs/conflict/expected.txt -// RUN: not clang-apply-replacements %T/Inputs/conflict > %T/Inputs/conflict/output.txt 2>&1 -// RUN: diff -b %T/Inputs/conflict/output.txt %T/Inputs/conflict/expected.txt +// RUN: mkdir -p %t.dir/Inputs/conflict +// RUN: sed "s#\$(path)#%/S/Inputs/conflict#" %S/Inputs/conflict/file1.yaml > %t.dir/Inputs/conflict/file1.yaml +// RUN: sed "s#\$(path)#%/S/Inputs/conflict#" %S/Inputs/conflict/file2.yaml > %t.dir/Inputs/conflict/file2.yaml +// RUN: sed "s#\$(path)#%/S/Inputs/conflict#" %S/Inputs/conflict/file3.yaml > %t.dir/Inputs/conflict/file3.yaml +// RUN: sed "s#\$(path)#%/S/Inputs/conflict#" %S/Inputs/conflict/expected.txt > %t.dir/Inputs/conflict/expected.txt +// RUN: not clang-apply-replacements %t.dir/Inputs/conflict > %t.dir/Inputs/conflict/output.txt 2>&1 +// RUN: diff -b %t.dir/Inputs/conflict/output.txt %t.dir/Inputs/conflict/expected.txt // // Check that the yaml files are *not* deleted after running clang-apply-replacements without remove-change-desc-files even when there is a failure. -// RUN: ls -1 %T/Inputs/conflict | FileCheck %s --check-prefix=YAML +// RUN: ls -1 %t.dir/Inputs/conflict | FileCheck %s --check-prefix=YAML // // Check that the yaml files *are* deleted after running clang-apply-replacements with remove-change-desc-files even when there is a failure. -// RUN: not clang-apply-replacements %T/Inputs/conflict -remove-change-desc-files > %T/Inputs/conflict/output.txt 2>&1 -// RUN: ls -1 %T/Inputs/conflict | FileCheck %s --check-prefix=NO_YAML +// RUN: not clang-apply-replacements %t.dir/Inputs/conflict -remove-change-desc-files > %t.dir/Inputs/conflict/output.txt 2>&1 +// RUN: ls -1 %t.dir/Inputs/conflict | FileCheck %s --check-prefix=NO_YAML // // YAML: {{^file.\.yaml$}} // NO_YAML-NOT: {{^file.\.yaml$}} diff --git a/clang-tools-extra/test/clang-apply-replacements/crlf.cpp b/clang-tools-extra/test/clang-apply-replacements/crlf.cpp index 15ba5b5..f40429e 100644 --- a/clang-tools-extra/test/clang-apply-replacements/crlf.cpp +++ b/clang-tools-extra/test/clang-apply-replacements/crlf.cpp @@ -1,5 +1,5 @@ -// RUN: mkdir -p %T/Inputs/crlf -// RUN: cat %S/Inputs/crlf/crlf.cpp > %T/Inputs/crlf/crlf.cpp -// RUN: sed "s#\$(path)#%/T/Inputs/crlf#" %S/Inputs/crlf/file1.yaml > %T/Inputs/crlf/file1.yaml -// RUN: clang-apply-replacements %T/Inputs/crlf -// RUN: diff %T/Inputs/crlf/crlf.cpp %S/Inputs/crlf/crlf.cpp.expected +// RUN: mkdir -p %t.dir/Inputs/crlf +// RUN: cat %S/Inputs/crlf/crlf.cpp > %t.dir/Inputs/crlf/crlf.cpp +// RUN: sed "s#\$(path)#%/t.dir/Inputs/crlf#" %S/Inputs/crlf/file1.yaml > %t.dir/Inputs/crlf/file1.yaml +// RUN: clang-apply-replacements %t.dir/Inputs/crlf +// RUN: diff %t.dir/Inputs/crlf/crlf.cpp %S/Inputs/crlf/crlf.cpp.expected diff --git a/clang-tools-extra/test/clang-apply-replacements/format-header.cpp b/clang-tools-extra/test/clang-apply-replacements/format-header.cpp index 6a221c4..9d2680e 100644 --- a/clang-tools-extra/test/clang-apply-replacements/format-header.cpp +++ b/clang-tools-extra/test/clang-apply-replacements/format-header.cpp @@ -1,13 +1,13 @@ -// RUN: mkdir -p %T/Inputs/format_header_yes -// RUN: mkdir -p %T/Inputs/format_header_no +// RUN: mkdir -p %t.dir/Inputs/format_header_yes +// RUN: mkdir -p %t.dir/Inputs/format_header_no // // -// RUN: grep -Ev "// *[A-Z-]+:" %S/Inputs/format_header/yes.cpp > %T/Inputs/format_header_yes/yes.cpp -// RUN: grep -Ev "// *[A-Z-]+:" %S/Inputs/format_header/no.cpp > %T/Inputs/format_header_no/no.cpp -// RUN: sed "s#\$(path)#%/T/Inputs/format_header_yes#" %S/Inputs/format_header/yes.yaml > %T/Inputs/format_header_yes/yes.yaml -// RUN: sed "s#\$(path)#%/T/Inputs/format_header_no#" %S/Inputs/format_header/no.yaml > %T/Inputs/format_header_no/no.yaml -// RUN: clang-apply-replacements -format -style="{BasedOnStyle: llvm, SortIncludes: CaseSensitive}" %T/Inputs/format_header_yes -// RUN: clang-apply-replacements %T/Inputs/format_header_no -// RUN: FileCheck --strict-whitespace -input-file=%T/Inputs/format_header_yes/yes.cpp %S/Inputs/format_header/yes.cpp -// RUN: FileCheck --strict-whitespace -input-file=%T/Inputs/format_header_no/no.cpp %S/Inputs/format_header/no.cpp +// RUN: grep -Ev "// *[A-Z-]+:" %S/Inputs/format_header/yes.cpp > %t.dir/Inputs/format_header_yes/yes.cpp +// RUN: grep -Ev "// *[A-Z-]+:" %S/Inputs/format_header/no.cpp > %t.dir/Inputs/format_header_no/no.cpp +// RUN: sed "s#\$(path)#%/t.dir/Inputs/format_header_yes#" %S/Inputs/format_header/yes.yaml > %t.dir/Inputs/format_header_yes/yes.yaml +// RUN: sed "s#\$(path)#%/t.dir/Inputs/format_header_no#" %S/Inputs/format_header/no.yaml > %t.dir/Inputs/format_header_no/no.yaml +// RUN: clang-apply-replacements -format -style="{BasedOnStyle: llvm, SortIncludes: CaseSensitive}" %t.dir/Inputs/format_header_yes +// RUN: clang-apply-replacements %t.dir/Inputs/format_header_no +// RUN: FileCheck --strict-whitespace -input-file=%t.dir/Inputs/format_header_yes/yes.cpp %S/Inputs/format_header/yes.cpp +// RUN: FileCheck --strict-whitespace -input-file=%t.dir/Inputs/format_header_no/no.cpp %S/Inputs/format_header/no.cpp // diff --git a/clang-tools-extra/test/clang-apply-replacements/format.cpp b/clang-tools-extra/test/clang-apply-replacements/format.cpp index 7de320d..0f40ef62 100644 --- a/clang-tools-extra/test/clang-apply-replacements/format.cpp +++ b/clang-tools-extra/test/clang-apply-replacements/format.cpp @@ -1,15 +1,15 @@ -// RUN: mkdir -p %T/Inputs/format +// RUN: mkdir -p %t.dir/Inputs/format // // yes.cpp requires formatting after replacements are applied. no.cpp does not. // The presence of no.cpp ensures that files that don't need formatting still // have their new state written to disk after applying replacements. // -// RUN: grep -Ev "// *[A-Z-]+:" %S/Inputs/format/yes.cpp > %T/Inputs/format/yes.cpp -// RUN: grep -Ev "// *[A-Z-]+:" %S/Inputs/format/no.cpp > %T/Inputs/format/no.cpp -// RUN: sed "s#\$(path)#%/T/Inputs/format#" %S/Inputs/format/yes.yaml > %T/Inputs/format/yes.yaml -// RUN: sed "s#\$(path)#%/T/Inputs/format#" %S/Inputs/format/no.yaml > %T/Inputs/format/no.yaml -// RUN: clang-apply-replacements -format %T/Inputs/format -// RUN: FileCheck --strict-whitespace -input-file=%T/Inputs/format/yes.cpp %S/Inputs/format/yes.cpp -// RUN: FileCheck --strict-whitespace -input-file=%T/Inputs/format/no.cpp %S/Inputs/format/no.cpp +// RUN: grep -Ev "// *[A-Z-]+:" %S/Inputs/format/yes.cpp > %t.dir/Inputs/format/yes.cpp +// RUN: grep -Ev "// *[A-Z-]+:" %S/Inputs/format/no.cpp > %t.dir/Inputs/format/no.cpp +// RUN: sed "s#\$(path)#%/t.dir/Inputs/format#" %S/Inputs/format/yes.yaml > %t.dir/Inputs/format/yes.yaml +// RUN: sed "s#\$(path)#%/t.dir/Inputs/format#" %S/Inputs/format/no.yaml > %t.dir/Inputs/format/no.yaml +// RUN: clang-apply-replacements -format %t.dir/Inputs/format +// RUN: FileCheck --strict-whitespace -input-file=%t.dir/Inputs/format/yes.cpp %S/Inputs/format/yes.cpp +// RUN: FileCheck --strict-whitespace -input-file=%t.dir/Inputs/format/no.cpp %S/Inputs/format/no.cpp // -// RUN not clang-apply-replacements -format=blah %T/Inputs/format +// RUN not clang-apply-replacements -format=blah %t.dir/Inputs/format diff --git a/clang-tools-extra/test/clang-apply-replacements/identical-in-TU.cpp b/clang-tools-extra/test/clang-apply-replacements/identical-in-TU.cpp index 024db11..df9c4fc 100644 --- a/clang-tools-extra/test/clang-apply-replacements/identical-in-TU.cpp +++ b/clang-tools-extra/test/clang-apply-replacements/identical-in-TU.cpp @@ -1,10 +1,10 @@ -// RUN: mkdir -p %T/Inputs/identical-in-TU +// RUN: mkdir -p %t.dir/Inputs/identical-in-TU -// RUN: grep -Ev "// *[A-Z-]+:" %S/Inputs/identical-in-TU/identical-in-TU.cpp > %T/Inputs/identical-in-TU/identical-in-TU.cpp -// RUN: sed "s#\$(path)#%/T/Inputs/identical-in-TU#" %S/Inputs/identical-in-TU/file1.yaml > %T/Inputs/identical-in-TU/file1.yaml -// RUN: sed "s#\$(path)#%/T/Inputs/identical-in-TU#" %S/Inputs/identical-in-TU/file2.yaml > %T/Inputs/identical-in-TU/file2.yaml -// RUN: clang-apply-replacements %T/Inputs/identical-in-TU -// RUN: FileCheck -input-file=%T/Inputs/identical-in-TU/identical-in-TU.cpp %S/Inputs/identical-in-TU/identical-in-TU.cpp +// RUN: grep -Ev "// *[A-Z-]+:" %S/Inputs/identical-in-TU/identical-in-TU.cpp > %t.dir/Inputs/identical-in-TU/identical-in-TU.cpp +// RUN: sed "s#\$(path)#%/t.dir/Inputs/identical-in-TU#" %S/Inputs/identical-in-TU/file1.yaml > %t.dir/Inputs/identical-in-TU/file1.yaml +// RUN: sed "s#\$(path)#%/t.dir/Inputs/identical-in-TU#" %S/Inputs/identical-in-TU/file2.yaml > %t.dir/Inputs/identical-in-TU/file2.yaml +// RUN: clang-apply-replacements %t.dir/Inputs/identical-in-TU +// RUN: FileCheck -input-file=%t.dir/Inputs/identical-in-TU/identical-in-TU.cpp %S/Inputs/identical-in-TU/identical-in-TU.cpp // Similar to identical test but each yaml file contains the same fix twice. // This check ensures that only the duplicated replacements in a single yaml diff --git a/clang-tools-extra/test/clang-apply-replacements/identical.cpp b/clang-tools-extra/test/clang-apply-replacements/identical.cpp index ffbf2e3..8a2d1e5 100644 --- a/clang-tools-extra/test/clang-apply-replacements/identical.cpp +++ b/clang-tools-extra/test/clang-apply-replacements/identical.cpp @@ -1,6 +1,6 @@ -// RUN: mkdir -p %T/Inputs/identical -// RUN: grep -Ev "// *[A-Z-]+:" %S/Inputs/identical/identical.cpp > %T/Inputs/identical/identical.cpp -// RUN: sed "s#\$(path)#%/T/Inputs/identical#" %S/Inputs/identical/file1.yaml > %T/Inputs/identical/file1.yaml -// RUN: sed "s#\$(path)#%/T/Inputs/identical#" %S/Inputs/identical/file2.yaml > %T/Inputs/identical/file2.yaml -// RUN: clang-apply-replacements %T/Inputs/identical -// RUN: FileCheck -input-file=%T/Inputs/identical/identical.cpp %S/Inputs/identical/identical.cpp +// RUN: mkdir -p %t.dir/Inputs/identical +// RUN: grep -Ev "// *[A-Z-]+:" %S/Inputs/identical/identical.cpp > %t.dir/Inputs/identical/identical.cpp +// RUN: sed "s#\$(path)#%/t.dir/Inputs/identical#" %S/Inputs/identical/file1.yaml > %t.dir/Inputs/identical/file1.yaml +// RUN: sed "s#\$(path)#%/t.dir/Inputs/identical#" %S/Inputs/identical/file2.yaml > %t.dir/Inputs/identical/file2.yaml +// RUN: clang-apply-replacements %t.dir/Inputs/identical +// RUN: FileCheck -input-file=%t.dir/Inputs/identical/identical.cpp %S/Inputs/identical/identical.cpp diff --git a/clang-tools-extra/test/clang-apply-replacements/ignore-conflict.cpp b/clang-tools-extra/test/clang-apply-replacements/ignore-conflict.cpp index 4e681dd..e310256 100644 --- a/clang-tools-extra/test/clang-apply-replacements/ignore-conflict.cpp +++ b/clang-tools-extra/test/clang-apply-replacements/ignore-conflict.cpp @@ -1,5 +1,5 @@ -// RUN: mkdir -p %T/Inputs/ignore-conflict -// RUN: grep -Ev "// *[A-Z-]+:" %S/Inputs/ignore-conflict/ignore-conflict.cpp > %T/Inputs/ignore-conflict/ignore-conflict.cpp -// RUN: sed "s#\$(path)#%/T/Inputs/ignore-conflict#" %S/Inputs/ignore-conflict/file1.yaml > %T/Inputs/ignore-conflict/file1.yaml -// RUN: clang-apply-replacements --ignore-insert-conflict %T/Inputs/ignore-conflict -// RUN: FileCheck -input-file=%T/Inputs/ignore-conflict/ignore-conflict.cpp %S/Inputs/ignore-conflict/ignore-conflict.cpp +// RUN: mkdir -p %t.dir/Inputs/ignore-conflict +// RUN: grep -Ev "// *[A-Z-]+:" %S/Inputs/ignore-conflict/ignore-conflict.cpp > %t.dir/Inputs/ignore-conflict/ignore-conflict.cpp +// RUN: sed "s#\$(path)#%/t.dir/Inputs/ignore-conflict#" %S/Inputs/ignore-conflict/file1.yaml > %t.dir/Inputs/ignore-conflict/file1.yaml +// RUN: clang-apply-replacements --ignore-insert-conflict %t.dir/Inputs/ignore-conflict +// RUN: FileCheck -input-file=%t.dir/Inputs/ignore-conflict/ignore-conflict.cpp %S/Inputs/ignore-conflict/ignore-conflict.cpp diff --git a/clang-tools-extra/test/clang-apply-replacements/invalid-files.cpp b/clang-tools-extra/test/clang-apply-replacements/invalid-files.cpp index b0eb9ef..09efd4c 100644 --- a/clang-tools-extra/test/clang-apply-replacements/invalid-files.cpp +++ b/clang-tools-extra/test/clang-apply-replacements/invalid-files.cpp @@ -1,6 +1,6 @@ -// RUN: mkdir -p %T/invalid-files -// RUN: cp %S/Inputs/invalid-files/invalid-files.yaml %T/invalid-files/invalid-files.yaml -// RUN: clang-apply-replacements %T/invalid-files +// RUN: mkdir -p %t.dir/invalid-files +// RUN: cp %S/Inputs/invalid-files/invalid-files.yaml %t.dir/invalid-files/invalid-files.yaml +// RUN: clang-apply-replacements %t.dir/invalid-files // // Check that the yaml files are *not* deleted after running clang-apply-replacements without remove-change-desc-files. -// RUN: ls %T/invalid-files/invalid-files.yaml +// RUN: ls %t.dir/invalid-files/invalid-files.yaml diff --git a/clang-tools-extra/test/clang-apply-replacements/order-dependent.cpp b/clang-tools-extra/test/clang-apply-replacements/order-dependent.cpp index 769f4f7..32a3bd1 100644 --- a/clang-tools-extra/test/clang-apply-replacements/order-dependent.cpp +++ b/clang-tools-extra/test/clang-apply-replacements/order-dependent.cpp @@ -1,7 +1,7 @@ -// RUN: mkdir -p %T/Inputs/order-dependent -// RUN: grep -Ev "// *[A-Z-]+:" %S/Inputs/order-dependent/order-dependent.cpp > %T/Inputs/order-dependent/order-dependent.cpp -// RUN: sed "s#\$(path)#%/T/Inputs/order-dependent#" %S/Inputs/order-dependent/file1.yaml > %T/Inputs/order-dependent/file1.yaml -// RUN: sed "s#\$(path)#%/T/Inputs/order-dependent#" %S/Inputs/order-dependent/file2.yaml > %T/Inputs/order-dependent/file2.yaml -// RUN: sed "s#\$(path)#%/T/Inputs/order-dependent#" %S/Inputs/order-dependent/expected.txt > %T/Inputs/order-dependent/expected.txt -// RUN: not clang-apply-replacements %T/Inputs/order-dependent > %T/Inputs/order-dependent/output.txt 2>&1 -// RUN: diff -b %T/Inputs/order-dependent/output.txt %T/Inputs/order-dependent/expected.txt +// RUN: mkdir -p %t.dir/Inputs/order-dependent +// RUN: grep -Ev "// *[A-Z-]+:" %S/Inputs/order-dependent/order-dependent.cpp > %t.dir/Inputs/order-dependent/order-dependent.cpp +// RUN: sed "s#\$(path)#%/t.dir/Inputs/order-dependent#" %S/Inputs/order-dependent/file1.yaml > %t.dir/Inputs/order-dependent/file1.yaml +// RUN: sed "s#\$(path)#%/t.dir/Inputs/order-dependent#" %S/Inputs/order-dependent/file2.yaml > %t.dir/Inputs/order-dependent/file2.yaml +// RUN: sed "s#\$(path)#%/t.dir/Inputs/order-dependent#" %S/Inputs/order-dependent/expected.txt > %t.dir/Inputs/order-dependent/expected.txt +// RUN: not clang-apply-replacements %t.dir/Inputs/order-dependent > %t.dir/Inputs/order-dependent/output.txt 2>&1 +// RUN: diff -b %t.dir/Inputs/order-dependent/output.txt %t.dir/Inputs/order-dependent/expected.txt diff --git a/clang-tools-extra/test/clang-apply-replacements/relative-paths.cpp b/clang-tools-extra/test/clang-apply-replacements/relative-paths.cpp index 92cde84..36e3e89 100644 --- a/clang-tools-extra/test/clang-apply-replacements/relative-paths.cpp +++ b/clang-tools-extra/test/clang-apply-replacements/relative-paths.cpp @@ -1,7 +1,7 @@ -// RUN: mkdir -p %T/Inputs/relative-paths -// RUN: mkdir -p %T/Inputs/relative-paths/subdir -// RUN: grep -Ev "// *[A-Z-]+:" %S/Inputs/relative-paths/basic.h > %T/Inputs/relative-paths/basic.h -// RUN: sed "s#\$(path)#%/T/Inputs/relative-paths#" %S/Inputs/relative-paths/file1.yaml > %T/Inputs/relative-paths/file1.yaml -// RUN: sed "s#\$(path)#%/T/Inputs/relative-paths#" %S/Inputs/relative-paths/file2.yaml > %T/Inputs/relative-paths/file2.yaml -// RUN: clang-apply-replacements %T/Inputs/relative-paths -// RUN: FileCheck -input-file=%T/Inputs/relative-paths/basic.h %S/Inputs/relative-paths/basic.h +// RUN: mkdir -p %t.dir/Inputs/relative-paths +// RUN: mkdir -p %t.dir/Inputs/relative-paths/subdir +// RUN: grep -Ev "// *[A-Z-]+:" %S/Inputs/relative-paths/basic.h > %t.dir/Inputs/relative-paths/basic.h +// RUN: sed "s#\$(path)#%/t.dir/Inputs/relative-paths#" %S/Inputs/relative-paths/file1.yaml > %t.dir/Inputs/relative-paths/file1.yaml +// RUN: sed "s#\$(path)#%/t.dir/Inputs/relative-paths#" %S/Inputs/relative-paths/file2.yaml > %t.dir/Inputs/relative-paths/file2.yaml +// RUN: clang-apply-replacements %t.dir/Inputs/relative-paths +// RUN: FileCheck -input-file=%t.dir/Inputs/relative-paths/basic.h %S/Inputs/relative-paths/basic.h diff --git a/clang-tools-extra/test/clang-apply-replacements/yml-basic.cpp b/clang-tools-extra/test/clang-apply-replacements/yml-basic.cpp index e6ee919..e076ff7 100644 --- a/clang-tools-extra/test/clang-apply-replacements/yml-basic.cpp +++ b/clang-tools-extra/test/clang-apply-replacements/yml-basic.cpp @@ -1,17 +1,17 @@ -// RUN: mkdir -p %T/Inputs/yml-basic -// RUN: grep -Ev "// *[A-Z-]+:" %S/Inputs/yml-basic/basic.h > %T/Inputs/yml-basic/basic.h -// RUN: sed "s#\$(path)#%/T/Inputs/yml-basic#" %S/Inputs/yml-basic/file1.yml > %T/Inputs/yml-basic/file1.yml -// RUN: sed "s#\$(path)#%/T/Inputs/yml-basic#" %S/Inputs/yml-basic/file2.yml > %T/Inputs/yml-basic/file2.yml -// RUN: clang-apply-replacements %T/Inputs/yml-basic -// RUN: FileCheck -input-file=%T/Inputs/yml-basic/basic.h %S/Inputs/yml-basic/basic.h +// RUN: mkdir -p %t.dir/Inputs/yml-basic +// RUN: grep -Ev "// *[A-Z-]+:" %S/Inputs/yml-basic/basic.h > %t.dir/Inputs/yml-basic/basic.h +// RUN: sed "s#\$(path)#%/t.dir/Inputs/yml-basic#" %S/Inputs/yml-basic/file1.yml > %t.dir/Inputs/yml-basic/file1.yml +// RUN: sed "s#\$(path)#%/t.dir/Inputs/yml-basic#" %S/Inputs/yml-basic/file2.yml > %t.dir/Inputs/yml-basic/file2.yml +// RUN: clang-apply-replacements %t.dir/Inputs/yml-basic +// RUN: FileCheck -input-file=%t.dir/Inputs/yml-basic/basic.h %S/Inputs/yml-basic/basic.h // // Check that the yml files are *not* deleted after running clang-apply-replacements without remove-change-desc-files. -// RUN: ls -1 %T/Inputs/yml-basic | FileCheck %s --check-prefix=YML +// RUN: ls -1 %t.dir/Inputs/yml-basic | FileCheck %s --check-prefix=YML // // Check that the yml files *are* deleted after running clang-apply-replacements with remove-change-desc-files. -// RUN: grep -Ev "// *[A-Z-]+:" %S/Inputs/yml-basic/basic.h > %T/Inputs/yml-basic/basic.h -// RUN: clang-apply-replacements -remove-change-desc-files %T/Inputs/yml-basic -// RUN: ls -1 %T/Inputs/yml-basic | FileCheck %s --check-prefix=NO_YML +// RUN: grep -Ev "// *[A-Z-]+:" %S/Inputs/yml-basic/basic.h > %t.dir/Inputs/yml-basic/basic.h +// RUN: clang-apply-replacements -remove-change-desc-files %t.dir/Inputs/yml-basic +// RUN: ls -1 %t.dir/Inputs/yml-basic | FileCheck %s --check-prefix=NO_YML // // YML: {{^file.\.yml$}} // NO_YML-NOT: {{^file.\.yml$}} diff --git a/clang-tools-extra/test/clang-change-namespace/allow-list.cpp b/clang-tools-extra/test/clang-change-namespace/allow-list.cpp index 7a941dcb..3b0d5b9 100644 --- a/clang-tools-extra/test/clang-change-namespace/allow-list.cpp +++ b/clang-tools-extra/test/clang-change-namespace/allow-list.cpp @@ -1,5 +1,5 @@ -// RUN: echo "^std::.*$" > %T/allow-list.txt -// RUN: clang-change-namespace -old_namespace "na::nb" -new_namespace "x::y" --file_pattern ".*" --allowed_file %T/allow-list.txt %s -- | sed 's,// CHECK.*,,' | FileCheck %s +// RUN: echo "^std::.*$" > %t.allow-list.txt +// RUN: clang-change-namespace -old_namespace "na::nb" -new_namespace "x::y" --file_pattern ".*" --allowed_file %t.allow-list.txt %s -- | sed 's,// CHECK.*,,' | FileCheck %s #include "Inputs/fake-std.h" diff --git a/clang-tools-extra/test/clang-change-namespace/macro.cpp b/clang-tools-extra/test/clang-change-namespace/macro.cpp index 40c4caf..f0b134d 100644 --- a/clang-tools-extra/test/clang-change-namespace/macro.cpp +++ b/clang-tools-extra/test/clang-change-namespace/macro.cpp @@ -1,15 +1,16 @@ -// RUN: cp %S/macro.cpp %T/macro.cpp -// RUN: echo "#define USING using na::nc::X" > %T/macro.h +// RUN: mkdir -p %t.dir +// RUN: cp %S/macro.cpp %t.dir/macro.cpp +// RUN: echo "#define USING using na::nc::X" > %t.dir/macro.h // -// RUN: clang-change-namespace -old_namespace "na::nb" -new_namespace "x::y" --file_pattern "macro.cpp$" --i %T/macro.cpp -- -// RUN: FileCheck -input-file=%T/macro.cpp -check-prefix=CHECK-CC %s -// RUN: FileCheck -input-file=%T/macro.h -check-prefix=CHECK-HEADER %s +// RUN: clang-change-namespace -old_namespace "na::nb" -new_namespace "x::y" --file_pattern "macro.cpp$" --i %t.dir/macro.cpp -- +// RUN: FileCheck -input-file=%t.dir/macro.cpp -check-prefix=CHECK-CC %s +// RUN: FileCheck -input-file=%t.dir/macro.h -check-prefix=CHECK-HEADER %s // -// RUN: cp %S/macro.cpp %T/macro.cpp -// RUN: echo "#define USING using na::nc::X" > %T/macro.h -// RUN: clang-change-namespace -old_namespace "na::nb" -new_namespace "x::y" --file_pattern ".*" --i %T/macro.cpp -- -// RUN: FileCheck -input-file=%T/macro.cpp -check-prefix=CHECK-CC %s -// RUN: FileCheck -input-file=%T/macro.h -check-prefix=CHECK-CHANGED-HEADER %s +// RUN: cp %S/macro.cpp %t.dir/macro.cpp +// RUN: echo "#define USING using na::nc::X" > %t.dir/macro.h +// RUN: clang-change-namespace -old_namespace "na::nb" -new_namespace "x::y" --file_pattern ".*" --i %t.dir/macro.cpp -- +// RUN: FileCheck -input-file=%t.dir/macro.cpp -check-prefix=CHECK-CC %s +// RUN: FileCheck -input-file=%t.dir/macro.h -check-prefix=CHECK-CHANGED-HEADER %s #include "macro.h" namespace na { namespace nc { class X{}; } } diff --git a/clang-tools-extra/test/clang-doc/Inputs/basic-project/include/Circle.h b/clang-tools-extra/test/clang-doc/Inputs/basic-project/include/Circle.h index 7bee3ff..74bffcd 100644 --- a/clang-tools-extra/test/clang-doc/Inputs/basic-project/include/Circle.h +++ b/clang-tools-extra/test/clang-doc/Inputs/basic-project/include/Circle.h @@ -26,6 +26,10 @@ public: /** * @brief Calculates the perimeter of the circle. * + * @code + * Circle circle(5.0); + * double perimeter = circle.perimeter(); + * @endcode * @return double The perimeter of the circle. */ double perimeter() const override; diff --git a/clang-tools-extra/test/clang-doc/basic-project.mustache.test b/clang-tools-extra/test/clang-doc/basic-project.mustache.test index 7bfdd4b..e2d9da6 100644 --- a/clang-tools-extra/test/clang-doc/basic-project.mustache.test +++ b/clang-tools-extra/test/clang-doc/basic-project.mustache.test @@ -2,17 +2,17 @@ // RUN: sed 's|$test_dir|%/S|g' %S/Inputs/basic-project/database_template.json > %t/build/compile_commands.json // RUN: clang-doc --format=mustache --output=%t/docs --executor=all-TUs %t/build/compile_commands.json -// RUN: FileCheck %s -input-file=%t/docs/GlobalNamespace/Shape.html -check-prefix=HTML-SHAPE -// RUN: FileCheck %s -input-file=%t/docs/GlobalNamespace/Calculator.html -check-prefix=HTML-CALC -// RUN: FileCheck %s -input-file=%t/docs/GlobalNamespace/Rectangle.html -check-prefix=HTML-RECTANGLE -// RUN: FileCheck %s -input-file=%t/docs/GlobalNamespace/Circle.html -check-prefix=HTML-CIRCLE +// RUN: FileCheck %s -input-file=%t/docs/_ZTV5Shape.html -check-prefix=HTML-SHAPE +// RUN: FileCheck %s -input-file=%t/docs/_ZTV10Calculator.html -check-prefix=HTML-CALC +// RUN: FileCheck %s -input-file=%t/docs/_ZTV9Rectangle.html -check-prefix=HTML-RECTANGLE +// RUN: FileCheck %s -input-file=%t/docs/_ZTV6Circle.html -check-prefix=HTML-CIRCLE HTML-SHAPE: <html lang="en-US"> HTML-SHAPE: <head> HTML-SHAPE: <meta charset="utf-8"/> HTML-SHAPE: <title>Shape</title> -HTML-SHAPE: <link rel="stylesheet" type="text/css" href="../clang-doc-mustache.css"/> -HTML-SHAPE: <script src="../mustache-index.js"></script> +HTML-SHAPE: <link rel="stylesheet" type="text/css" href="./clang-doc-mustache.css"/> +HTML-SHAPE: <script src="./mustache-index.js"></script> HTML-SHAPE: <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/default.min.css"> HTML-SHAPE: <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script> HTML-SHAPE: <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/cpp.min.js"></script> @@ -60,6 +60,17 @@ HTML-SHAPE: <div class="content"> HTML-SHAPE: <section class="hero section-container"> HTML-SHAPE: <div class="hero__title"> HTML-SHAPE: <h1 class="hero__title-large">class Shape</h1> +HTML-SHAPE: <div class="hero__subtitle"> +HTML-SHAPE: <div> +HTML-SHAPE: <p> Abstract base class for shapes.</p> +HTML-SHAPE: </div> +HTML-SHAPE: <div> +HTML-SHAPE: <p></p> +HTML-SHAPE: </div> +HTML-SHAPE: <div> +HTML-SHAPE: <p> Provides a common interface for different types of shapes.</p> +HTML-SHAPE: </div> +HTML-SHAPE: </div> HTML-SHAPE: </div> HTML-SHAPE: </section> HTML-SHAPE: <section id="PublicMethods" class="section-container"> @@ -72,6 +83,19 @@ HTML-SHAPE: <code class="language-cpp code-clang-doc"> HTML-SHAPE: double area () HTML-SHAPE: </code> HTML-SHAPE: </pre> +HTML-SHAPE: <div> +HTML-SHAPE: <div> +HTML-SHAPE: <p> Calculates the area of the shape.</p> +HTML-SHAPE: </div> +HTML-SHAPE: <div> +HTML-SHAPE: <p></p> +HTML-SHAPE: </div> +HTML-SHAPE: <div> +HTML-SHAPE: <p></p> +HTML-SHAPE: </div> +HTML-SHAPE: <h3>Returns</h3> +HTML-SHAPE: <p> double The area of the shape.</p> +HTML-SHAPE: </div> HTML-SHAPE: </div> HTML-SHAPE: </div> HTML-SHAPE: <div class="delimiter-container"> @@ -81,6 +105,19 @@ HTML-SHAPE: <code class="language-cpp code-clang-doc"> HTML-SHAPE: double perimeter () HTML-SHAPE: </code> HTML-SHAPE: </pre> +HTML-SHAPE: <div> +HTML-SHAPE: <div> +HTML-SHAPE: <p> Calculates the perimeter of the shape.</p> +HTML-SHAPE: </div> +HTML-SHAPE: <div> +HTML-SHAPE: <p></p> +HTML-SHAPE: </div> +HTML-SHAPE: <div> +HTML-SHAPE: <p></p> +HTML-SHAPE: </div> +HTML-SHAPE: <h3>Returns</h3> +HTML-SHAPE: <p> double The perimeter of the shape.</p> +HTML-SHAPE: </div> HTML-SHAPE: </div> HTML-SHAPE: </div> HTML-SHAPE: <div class="delimiter-container"> @@ -90,6 +127,14 @@ HTML-SHAPE: <code class="language-cpp code-clang-doc"> HTML-SHAPE: void ~Shape () HTML-SHAPE: </code> HTML-SHAPE: </pre> +HTML-SHAPE: <div> +HTML-SHAPE: <div> +HTML-SHAPE: <p> Virtual destructor.</p> +HTML-SHAPE: </div> +HTML-SHAPE: <div> +HTML-SHAPE: <p></p> +HTML-SHAPE: </div> +HTML-SHAPE: </div> HTML-SHAPE: </div> HTML-SHAPE: </div> HTML-SHAPE: </div> @@ -106,8 +151,8 @@ HTML-CALC: <html lang="en-US"> HTML-CALC: <head> HTML-CALC: <meta charset="utf-8"/> HTML-CALC: <title>Calculator</title> -HTML-CALC: <link rel="stylesheet" type="text/css" href="../clang-doc-mustache.css"/> -HTML-CALC: <script src="../mustache-index.js"></script> +HTML-CALC: <link rel="stylesheet" type="text/css" href="./clang-doc-mustache.css"/> +HTML-CALC: <script src="./mustache-index.js"></script> HTML-CALC: <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/default.min.css"> HTML-CALC: <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script> HTML-CALC: <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/cpp.min.js"></script> @@ -135,7 +180,7 @@ HTML-CALC: <div class="sidebar"> HTML-CALC: <h2>class Calculator</h2> HTML-CALC: <ul> HTML-CALC: <li class="sidebar-section"> -HTML-CALC: <a class="sidebar-item" href="#PublicMethods">Public Members</a> +HTML-CALC: <a class="sidebar-item" href="#PublicMembers">Public Members</a> HTML-CALC: </li> HTML-CALC: <ul> HTML-CALC: <li class="sidebar-item-container"> @@ -172,6 +217,16 @@ HTML-CALC: <div class="content"> HTML-CALC: <section class="hero section-container"> HTML-CALC: <div class="hero__title"> HTML-CALC: <h1 class="hero__title-large">class Calculator</h1> +HTML-CALC: <div> +HTML-CALC: <p> A simple calculator class.</p> +HTML-CALC: </div> +HTML-CALC: <div> +HTML-CALC: <p></p> +HTML-CALC: </div> +HTML-CALC: <div> +HTML-CALC: <p> Provides basic arithmetic operations.</p> +HTML-CALC: </div> +HTML-CALC: </div> HTML-CALC: </div> HTML-CALC: </section> HTML-CALC: <section id="PublicMembers" class="section-container"> @@ -199,6 +254,36 @@ HTML-CALC: <code class="language-cpp code-clang-doc"> HTML-CALC: int add (int a, int b) HTML-CALC: </code> HTML-CALC: </pre> +HTML-CALC: <div> +HTML-CALC: <div> +HTML-CALC: <p> Adds two integers.</p> +HTML-CALC: </div> +HTML-CALC: <div> +HTML-CALC: <p></p> +HTML-CALC: </div> +HTML-CALC: <div> +HTML-CALC: <p></p> +HTML-CALC: </div> +HTML-CALC: <h3>Parameters</h3> +HTML-CALC: <div> +HTML-CALC: <b>a</b> <div> +HTML-CALC: <p> First integer.</p> +HTML-CALC: </div> +HTML-CALC: <div> +HTML-CALC: <p></p> +HTML-CALC: </div> +HTML-CALC: </div> +HTML-CALC: <div> +HTML-CALC: <b>b</b> <div> +HTML-CALC: <p> Second integer.</p> +HTML-CALC: </div> +HTML-CALC: <div> +HTML-CALC: <p></p> +HTML-CALC: </div> +HTML-CALC: </div> +HTML-CALC: <h3>Returns</h3> +HTML-CALC: <p> int The sum of a and b.</p> +HTML-CALC: </div> HTML-CALC: </div> HTML-CALC: </div> HTML-CALC: <div class="delimiter-container"> @@ -208,6 +293,19 @@ HTML-CALC: <code class="language-cpp code-clang-doc"> HTML-CALC: int subtract (int a, int b) HTML-CALC: </code> HTML-CALC: </pre> +HTML-CALC: <div> +HTML-CALC: <div> +HTML-CALC: <p> Subtracts the second integer from the first.</p> +HTML-CALC: </div> +HTML-CALC: <div> +HTML-CALC: <p></p> +HTML-CALC: </div> +HTML-CALC: <div> +HTML-CALC: <p></p> +HTML-CALC: </div> +HTML-CALC: <h3>Returns</h3> +HTML-CALC: <p> int The result of a - b.</p> +HTML-CALC: </div> HTML-CALC: </div> HTML-CALC: </div> HTML-CALC: <div class="delimiter-container"> @@ -217,6 +315,36 @@ HTML-CALC: <code class="language-cpp code-clang-doc"> HTML-CALC: int multiply (int a, int b) HTML-CALC: </code> HTML-CALC: </pre> +HTML-CALC: <div> +HTML-CALC: <div> +HTML-CALC: <p> Multiplies two integers.</p> +HTML-CALC: </div> +HTML-CALC: <div> +HTML-CALC: <p></p> +HTML-CALC: </div> +HTML-CALC: <div> +HTML-CALC: <p></p> +HTML-CALC: </div> +HTML-CALC: <h3>Parameters</h3> +HTML-CALC: <div> +HTML-CALC: <b>a</b> <div> +HTML-CALC: <p> First integer.</p> +HTML-CALC: </div> +HTML-CALC: <div> +HTML-CALC: <p></p> +HTML-CALC: </div> +HTML-CALC: </div> +HTML-CALC: <div> +HTML-CALC: <b>b</b> <div> +HTML-CALC: <p> Second integer.</p> +HTML-CALC: </div> +HTML-CALC: <div> +HTML-CALC: <p></p> +HTML-CALC: </div> +HTML-CALC: </div> +HTML-CALC: <h3>Returns</h3> +HTML-CALC: <p> int The product of a and b.</p> +HTML-CALC: </div> HTML-CALC: </div> HTML-CALC: </div> HTML-CALC: <div class="delimiter-container"> @@ -226,6 +354,37 @@ HTML-CALC: <code class="language-cpp code-clang-doc"> HTML-CALC: double divide (int a, int b) HTML-CALC: </code> HTML-CALC: </pre> +HTML-CALC: <div> +HTML-CALC: <div> +HTML-CALC: <p> Divides the first integer by the second.</p> +HTML-CALC: </div> +HTML-CALC: <div> +HTML-CALC: <p></p> +HTML-CALC: </div> +HTML-CALC: <div> +HTML-CALC: <p></p> +HTML-CALC: </div> +HTML-CALC: <h3>Parameters</h3> +HTML-CALC: <div> +HTML-CALC: <b>a</b> <div> +HTML-CALC: <p> First integer.</p> +HTML-CALC: </div> +HTML-CALC: <div> +HTML-CALC: <p></p> +HTML-CALC: </div> +HTML-CALC: </div> +HTML-CALC: <div> +HTML-CALC: <b>b</b> <div> +HTML-CALC: <p> Second integer.</p> +HTML-CALC: </div> +HTML-CALC: <div> +HTML-CALC: <p></p> +HTML-CALC: </div> +HTML-CALC: </div> +HTML-CALC: <h3>Returns</h3> +HTML-CALC: <p> double The result of a / b.</p> +HTML-CALC: <p></p> +HTML-CALC: </div> HTML-CALC: </div> HTML-CALC: </div> HTML-CALC: <div class="delimiter-container"> @@ -235,6 +394,36 @@ HTML-CALC: <code class="language-cpp code-clang-doc"> HTML-CALC: int mod (int a, int b) HTML-CALC: </code> HTML-CALC: </pre> +HTML-CALC: <div> +HTML-CALC: <div> +HTML-CALC: <p> Performs the mod operation on integers.</p> +HTML-CALC: </div> +HTML-CALC: <div> +HTML-CALC: <p></p> +HTML-CALC: </div> +HTML-CALC: <div> +HTML-CALC: <p></p> +HTML-CALC: </div> +HTML-CALC: <h3>Parameters</h3> +HTML-CALC: <div> +HTML-CALC: <b>a</b> <div> +HTML-CALC: <p> First integer.</p> +HTML-CALC: </div> +HTML-CALC: <div> +HTML-CALC: <p></p> +HTML-CALC: </div> +HTML-CALC: </div> +HTML-CALC: <div> +HTML-CALC: <b>b</b> <div> +HTML-CALC: <p> Second integer.</p> +HTML-CALC: </div> +HTML-CALC: <div> +HTML-CALC: <p></p> +HTML-CALC: </div> +HTML-CALC: </div> +HTML-CALC: <h3>Returns</h3> +HTML-CALC: <p> The result of a % b.</p> +HTML-CALC: </div> HTML-CALC: </div> HTML-CALC: </div> HTML-CALC: </div> @@ -251,8 +440,8 @@ HTML-RECTANGLE: <html lang="en-US"> HTML-RECTANGLE: <head> HTML-RECTANGLE: <meta charset="utf-8"/> HTML-RECTANGLE: <title>Rectangle</title> -HTML-RECTANGLE: <link rel="stylesheet" type="text/css" href="../clang-doc-mustache.css"/> -HTML-RECTANGLE: <script src="../mustache-index.js"></script> +HTML-RECTANGLE: <link rel="stylesheet" type="text/css" href="./clang-doc-mustache.css"/> +HTML-RECTANGLE: <script src="./mustache-index.js"></script> HTML-RECTANGLE: <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/default.min.css"> HTML-RECTANGLE: <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script> HTML-RECTANGLE: <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/cpp.min.js"></script> @@ -279,17 +468,6 @@ HTML-RECTANGLE: <div class="container"> HTML-RECTANGLE: <div class="sidebar"> HTML-RECTANGLE: <h2>class Rectangle</h2> HTML-RECTANGLE: <ul> -HTML-RECTANGLE: <li class="sidebar-section"> -HTML-RECTANGLE: <a class="sidebar-item" href="#PublicMethods">Protected Members</a> -HTML-RECTANGLE: </li> -HTML-RECTANGLE: <ul> -HTML-RECTANGLE: <li class="sidebar-item-container"> -HTML-RECTANGLE: <a class="sidebar-item" href="#width_">width_</a> -HTML-RECTANGLE: </li> -HTML-RECTANGLE: <li class="sidebar-item-container"> -HTML-RECTANGLE: <a class="sidebar-item" href="#height_">height_</a> -HTML-RECTANGLE: </li> -HTML-RECTANGLE: </ul> HTML-RECTANGLE: <li class="sidebar-section"> HTML-RECTANGLE: <a class="sidebar-item" href="#PublicMethods">Public Method</a> HTML-RECTANGLE: </li> @@ -311,21 +489,17 @@ HTML-RECTANGLE: <div class="content"> HTML-RECTANGLE: <section class="hero section-container"> HTML-RECTANGLE: <div class="hero__title"> HTML-RECTANGLE: <h1 class="hero__title-large">class Rectangle</h1> -HTML-RECTANGLE: </div> -HTML-RECTANGLE: </section> -HTML-RECTANGLE: <section id="ProtectedMembers" class="section-container"> -HTML-RECTANGLE: <h2>Protected Members</h2> -HTML-RECTANGLE: <div> -HTML-RECTANGLE: <div id="width_" class="delimiter-container"> -HTML-RECTANGLE: <pre> -HTML-RECTANGLE: <code class="language-cpp code-clang-doc" >double width_</code> -HTML-RECTANGLE: </pre> -HTML-RECTANGLE: </div> -HTML-RECTANGLE: <div id="height_" class="delimiter-container"> -HTML-RECTANGLE: <pre> -HTML-RECTANGLE: <code class="language-cpp code-clang-doc" >double height_</code> -HTML-RECTANGLE: </pre> -HTML-RECTANGLE: </div> +HTML-RECTANGLE: <div class="hero__subtitle"> +HTML-RECTANGLE: <div> +HTML-RECTANGLE: <p> Rectangle class derived from Shape.</p> +HTML-RECTANGLE: </div> +HTML-RECTANGLE: <div> +HTML-RECTANGLE: <p></p> +HTML-RECTANGLE: </div> +HTML-RECTANGLE: <div> +HTML-RECTANGLE: <p> Represents a rectangle with a given width and height.</p> +HTML-RECTANGLE: </div> +HTML-RECTANGLE: </div> HTML-RECTANGLE: </div> HTML-RECTANGLE: </section> HTML-RECTANGLE: <section id="PublicMethods" class="section-container"> @@ -338,6 +512,31 @@ HTML-RECTANGLE: <code class="language-cpp code-clang-doc"> HTML-RECTANGLE: void Rectangle (double width, double height) HTML-RECTANGLE: </code> HTML-RECTANGLE: </pre> +HTML-RECTANGLE: <div> +HTML-RECTANGLE: <div> +HTML-RECTANGLE: <p> Constructs a new Rectangle object.</p> +HTML-RECTANGLE: </div> +HTML-RECTANGLE: <div> +HTML-RECTANGLE: <p></p> +HTML-RECTANGLE: </div> +HTML-RECTANGLE: <div> +HTML-RECTANGLE: <p></p> +HTML-RECTANGLE: </div> +HTML-RECTANGLE: <h3>Parameters</h3> +HTML-RECTANGLE: <div> +HTML-RECTANGLE: <b>width</b> <div> +HTML-RECTANGLE: <p> Width of the rectangle.</p> +HTML-RECTANGLE: </div> +HTML-RECTANGLE: <div> +HTML-RECTANGLE: <p></p> +HTML-RECTANGLE: </div> +HTML-RECTANGLE: </div> +HTML-RECTANGLE: <div> +HTML-RECTANGLE: <b>height</b> <div> +HTML-RECTANGLE: <p> Height of the rectangle.</p> +HTML-RECTANGLE: </div> +HTML-RECTANGLE: </div> +HTML-RECTANGLE: </div> HTML-RECTANGLE: </div> HTML-RECTANGLE: </div> HTML-RECTANGLE: <div class="delimiter-container"> @@ -347,6 +546,19 @@ HTML-RECTANGLE: <code class="language-cpp code-clang-doc"> HTML-RECTANGLE: double area () HTML-RECTANGLE: </code> HTML-RECTANGLE: </pre> +HTML-RECTANGLE: <div> +HTML-RECTANGLE: <div> +HTML-RECTANGLE: <p> Calculates the area of the rectangle.</p> +HTML-RECTANGLE: </div> +HTML-RECTANGLE: <div> +HTML-RECTANGLE: <p></p> +HTML-RECTANGLE: </div> +HTML-RECTANGLE: <div> +HTML-RECTANGLE: <p></p> +HTML-RECTANGLE: </div> +HTML-RECTANGLE: <h3>Returns</h3> +HTML-RECTANGLE: <p> double The area of the rectangle.</p> +HTML-RECTANGLE: </div> HTML-RECTANGLE: </div> HTML-RECTANGLE: </div> HTML-RECTANGLE: <div class="delimiter-container"> @@ -356,6 +568,19 @@ HTML-RECTANGLE: <code class="language-cpp code-clang-doc"> HTML-RECTANGLE: double perimeter () HTML-RECTANGLE: </code> HTML-RECTANGLE: </pre> +HTML-RECTANGLE: <div> +HTML-RECTANGLE: <div> +HTML-RECTANGLE: <p> Calculates the perimeter of the rectangle.</p> +HTML-RECTANGLE: </div> +HTML-RECTANGLE: <div> +HTML-RECTANGLE: <p></p> +HTML-RECTANGLE: </div> +HTML-RECTANGLE: <div> +HTML-RECTANGLE: <p></p> +HTML-RECTANGLE: </div> +HTML-RECTANGLE: <h3>Returns</h3> +HTML-RECTANGLE: <p> double The perimeter of the rectangle.</p> +HTML-RECTANGLE: </div> HTML-RECTANGLE: </div> HTML-RECTANGLE: </div> HTML-RECTANGLE: </div> @@ -372,8 +597,8 @@ HTML-CIRCLE: <html lang="en-US"> HTML-CIRCLE: <head> HTML-CIRCLE: <meta charset="utf-8"/> HTML-CIRCLE: <title>Circle</title> -HTML-CIRCLE: <link rel="stylesheet" type="text/css" href="../clang-doc-mustache.css"/> -HTML-CIRCLE: <script src="../mustache-index.js"></script> +HTML-CIRCLE: <link rel="stylesheet" type="text/css" href="./clang-doc-mustache.css"/> +HTML-CIRCLE: <script src="./mustache-index.js"></script> HTML-CIRCLE: <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/default.min.css"> HTML-CIRCLE: <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script> HTML-CIRCLE: <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/cpp.min.js"></script> @@ -400,14 +625,6 @@ HTML-CIRCLE: <div class="container"> HTML-CIRCLE: <div class="sidebar"> HTML-CIRCLE: <h2>class Circle</h2> HTML-CIRCLE: <ul> -HTML-CIRCLE: <li class="sidebar-section"> -HTML-CIRCLE: <a class="sidebar-item" href="#PublicMethods">Protected Members</a> -HTML-CIRCLE: </li> -HTML-CIRCLE: <ul> -HTML-CIRCLE: <li class="sidebar-item-container"> -HTML-CIRCLE: <a class="sidebar-item" href="#radius_">radius_</a> -HTML-CIRCLE: </li> -HTML-CIRCLE: </ul> HTML-CIRCLE: <li class="sidebar-section"> HTML-CIRCLE: <a class="sidebar-item" href="#PublicMethods">Public Method</a> HTML-CIRCLE: </li> @@ -429,16 +646,17 @@ HTML-CIRCLE: <div class="content"> HTML-CIRCLE: <section class="hero section-container"> HTML-CIRCLE: <div class="hero__title"> HTML-CIRCLE: <h1 class="hero__title-large">class Circle</h1> -HTML-CIRCLE: </div> -HTML-CIRCLE: </section> -HTML-CIRCLE: <section id="ProtectedMembers" class="section-container"> -HTML-CIRCLE: <h2>Protected Members</h2> -HTML-CIRCLE: <div> -HTML-CIRCLE: <div id="radius_" class="delimiter-container"> -HTML-CIRCLE: <pre> -HTML-CIRCLE: <code class="language-cpp code-clang-doc" >double radius_</code> -HTML-CIRCLE: </pre> -HTML-CIRCLE: </div> +HTML-CIRCLE: <div class="hero__subtitle"> +HTML-CIRCLE: <div> +HTML-CIRCLE: <p> Circle class derived from Shape.</p> +HTML-CIRCLE: </div> +HTML-CIRCLE: <div> +HTML-CIRCLE: <p></p> +HTML-CIRCLE: </div> +HTML-CIRCLE: <div> +HTML-CIRCLE: <p> Represents a circle with a given radius.</p> +HTML-CIRCLE: </div> +HTML-CIRCLE: </div> HTML-CIRCLE: </div> HTML-CIRCLE: </section> HTML-CIRCLE: <section id="PublicMethods" class="section-container"> @@ -451,6 +669,23 @@ HTML-CIRCLE: <code class="language-cpp code-clang-doc"> HTML-CIRCLE: void Circle (double radius) HTML-CIRCLE: </code> HTML-CIRCLE: </pre> +HTML-CIRCLE: <div> +HTML-CIRCLE: <div> +HTML-CIRCLE: <p> Constructs a new Circle object.</p> +HTML-CIRCLE: </div> +HTML-CIRCLE: <div> +HTML-CIRCLE: <p></p> +HTML-CIRCLE: </div> +HTML-CIRCLE: <div> +HTML-CIRCLE: <p></p> +HTML-CIRCLE: </div> +HTML-CIRCLE: <h3>Parameters</h3> +HTML-CIRCLE: <div> +HTML-CIRCLE: <b>radius</b> <div> +HTML-CIRCLE: <p> Radius of the circle.</p> +HTML-CIRCLE: </div> +HTML-CIRCLE: </div> +HTML-CIRCLE: </div> HTML-CIRCLE: </div> HTML-CIRCLE: </div> HTML-CIRCLE: <div class="delimiter-container"> @@ -460,6 +695,19 @@ HTML-CIRCLE: <code class="language-cpp code-clang-doc"> HTML-CIRCLE: double area () HTML-CIRCLE: </code> HTML-CIRCLE: </pre> +HTML-CIRCLE: <div> +HTML-CIRCLE: <div> +HTML-CIRCLE: <p> Calculates the area of the circle.</p> +HTML-CIRCLE: </div> +HTML-CIRCLE: <div> +HTML-CIRCLE: <p></p> +HTML-CIRCLE: </div> +HTML-CIRCLE: <div> +HTML-CIRCLE: <p></p> +HTML-CIRCLE: </div> +HTML-CIRCLE: <h3>Returns</h3> +HTML-CIRCLE: <p> double The area of the circle.</p> +HTML-CIRCLE: </div> HTML-CIRCLE: </div> HTML-CIRCLE: </div> HTML-CIRCLE: <div class="delimiter-container"> @@ -469,6 +717,28 @@ HTML-CIRCLE: <code class="language-cpp code-clang-doc"> HTML-CIRCLE: double perimeter () HTML-CIRCLE: </code> HTML-CIRCLE: </pre> +HTML-CIRCLE: <div> +HTML-CIRCLE: <div> +HTML-CIRCLE: <p> Calculates the perimeter of the circle.</p> +HTML-CIRCLE: </div> +HTML-CIRCLE: <div> +HTML-CIRCLE: <p></p> +HTML-CIRCLE: </div> +HTML-CIRCLE: <div> +HTML-CIRCLE: <p></p> +HTML-CIRCLE: </div> +HTML-CIRCLE: <h3>Returns</h3> +HTML-CIRCLE: <p> double The perimeter of the circle.</p> +HTML-CIRCLE: <h3>Code</h3> +HTML-CIRCLE: <div> +HTML-CIRCLE: <pre class="code-block"> +HTML-CIRCLE: <code> +HTML-CIRCLE: Circle circle(5.0); +HTML-CIRCLE: double perimeter = circle.perimeter(); +HTML-CIRCLE: </code> +HTML-CIRCLE: </pre> +HTML-CIRCLE: </div> +HTML-CIRCLE: </div> HTML-CIRCLE: </div> HTML-CIRCLE: </div> HTML-CIRCLE: </div> diff --git a/clang-tools-extra/test/clang-doc/json/class-requires.cpp b/clang-tools-extra/test/clang-doc/json/class-requires.cpp index 213da93..bf6c889 100644 --- a/clang-tools-extra/test/clang-doc/json/class-requires.cpp +++ b/clang-tools-extra/test/clang-doc/json/class-requires.cpp @@ -20,6 +20,7 @@ struct MyClass; // CHECK-NEXT: "Template": { // CHECK-NEXT: "Constraints": [ // CHECK-NEXT: { +// CHECK-NEXT: "End": true, // CHECK-NEXT: "Expression": "Addable<T>", // CHECK-NEXT: "Name": "Addable", // CHECK-NEXT: "Path": "", diff --git a/clang-tools-extra/test/clang-doc/json/class-template.cpp b/clang-tools-extra/test/clang-doc/json/class-template.cpp index 6cdc3e9..149248c 100644 --- a/clang-tools-extra/test/clang-doc/json/class-template.cpp +++ b/clang-tools-extra/test/clang-doc/json/class-template.cpp @@ -11,6 +11,7 @@ template<typename T> struct MyClass { // CHECK: "Name": "method", // CHECK: "Params": [ // CHECK-NEXT: { +// CHECK-NEXT: "End": true, // CHECK-NEXT: "Name": "Param", // CHECK-NEXT: "Type": "T" // CHECK-NEXT: } diff --git a/clang-tools-extra/test/clang-doc/json/class.cpp b/clang-tools-extra/test/clang-doc/json/class.cpp index d8317ea..79b8fed 100644 --- a/clang-tools-extra/test/clang-doc/json/class.cpp +++ b/clang-tools-extra/test/clang-doc/json/class.cpp @@ -33,35 +33,29 @@ protected: }; // CHECK: { -// CHECK-NEXT: "Description": [ -// CHECK-NEXT: { -// CHECK-NEXT: "FullComment": { -// CHECK-NEXT: "Children": [ -// CHECK-NEXT: { -// CHECK-NEXT: "ParagraphComment": { -// CHECK-NEXT: "Children": [ -// CHECK-NEXT: { -// CHECK-NEXT: "TextComment": " This is a nice class." -// CHECK-NEXT: }, -// CHECK-NEXT: { -// CHECK-NEXT: "TextComment": " It has some nice methods and fields." -// CHECK-NEXT: }, -// CHECK-NEXT: { -// CHECK-NEXT: "TextComment": "" -// CHECK-NEXT: } -// CHECK-NEXT: ] -// CHECK: { -// CHECK-NEXT: "BlockCommandComment": { -// CHECK-NEXT: "Children": [ -// CHECK-NEXT: { -// CHECK-NEXT: "ParagraphComment": { -// CHECK-NEXT: "Children": [ -// CHECK-NEXT: { -// CHECK-NEXT: "TextComment": " This is a brief description." -// CHECK-NEXT: } -// CHECK: "Command": "brief" +// CHECK-NEXT: "Description": { +// CHECK-NEXT: "BriefComments": [ +// CHECK-NEXT: [ +// CHECK-NEXT: { +// CHECK-NEXT: "TextComment": " This is a brief description." +// CHECK: "HasBriefComments": true, +// CHECK-NEXT: "HasParagraphComments": true, +// CHECK-NEXT: "ParagraphComments": [ +// CHECK-NEXT: [ +// CHECK-NEXT: { +// CHECK-NEXT: "TextComment": " This is a nice class." +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "TextComment": " It has some nice methods and fields." +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "TextComment": "" +// CHECK-NEXT: } +// CHECK: "DocumentationFileName": "_ZTV7MyClass", // CHECK: "Enums": [ // CHECK-NEXT: { +// CHECK-NEXT: "End": true, +// CHECK-NEXT: "InfoType": "enum", // CHECK-NEXT: "Location": { // CHECK-NEXT: "Filename": "{{.*}}class.cpp", // CHECK-NEXT: "LineNumber": 17 @@ -76,6 +70,7 @@ protected: // CHECK-NEXT: "Value": "1" // CHECK-NEXT: }, // CHECK-NEXT: { +// CHECK-NEXT: "End": true, // CHECK-NEXT: "Name": "BLUE", // CHECK-NEXT: "ValueExpr": "5" // CHECK-NEXT: } @@ -94,6 +89,7 @@ protected: // CHECK-NEXT: "IsClass": false, // CHECK-NEXT: "Params": [ // CHECK-NEXT: { +// CHECK-NEXT: "End": true, // CHECK-NEXT: "Name": "", // CHECK-NEXT: "Type": "int" // CHECK-NEXT: } @@ -118,6 +114,7 @@ protected: // CHECK-NEXT: } // CHECK-NEXT: }, // CHECK-NEXT: { +// CHECK-NEXT: "End": true, // CHECK-NEXT: "IsClass": true, // CHECK-NEXT: "Reference": { // CHECK-NEXT: "Name": "Foo", @@ -129,6 +126,11 @@ protected: // CHECK-NEXT: ], // COM: FIXME: FullName is not emitted correctly. // CHECK-NEXT: "FullName": "", +// CHECK-NEXT: "HasEnums": true, +// CHECK-NEXT: "HasPublicFunctions": true, +// CHECK-NEXT: "HasPublicMembers": true, +// CHECK-NEXT: "HasRecords": true, +// CHECK-NEXT: "InfoType": "record", // CHECK-NEXT: "IsTypedef": false, // CHECK-NEXT: "Location": { // CHECK-NEXT: "Filename": "{{.*}}class.cpp", @@ -142,6 +144,7 @@ protected: // CHECK-NEXT: "Path": "GlobalNamespace", // CHECK-NEXT: "ProtectedFunctions": [ // CHECK-NEXT: { +// CHECK-NEXT: "InfoType": "function", // CHECK-NEXT: "IsStatic": false, // CHECK-NEXT: "Name": "protectedMethod", // CHECK-NEXT: "Namespace": [ @@ -166,6 +169,7 @@ protected: // CHECK-NEXT: ], // CHECK-NEXT: "PublicFunctions": [ // CHECK-NEXT: { +// CHECK-NEXT: "InfoType": "function", // CHECK-NEXT: "IsStatic": false, // CHECK-NEXT: "Name": "myMethod", // CHECK-NEXT: "Namespace": [ @@ -174,6 +178,7 @@ protected: // CHECK-NEXT: ], // CHECK-NEXT: "Params": [ // CHECK-NEXT: { +// CHECK-NEXT: "End": true, // CHECK-NEXT: "Name": "MyParam", // CHECK-NEXT: "Type": "int" // CHECK-NEXT: } @@ -204,6 +209,8 @@ protected: // CHECK-NEXT: ], // CHECK-NEXT: "Records": [ // CHECK-NEXT: { +// CHECK-NEXT: "DocumentationFileName": "_ZTVN7MyClass11NestedClassE", +// CHECK-NEXT: "End": true, // CHECK-NEXT: "Name": "NestedClass", // CHECK-NEXT: "Path": "GlobalNamespace{{[\/]+}}MyClass", // CHECK-NEXT: "QualName": "NestedClass", @@ -213,6 +220,8 @@ protected: // CHECK-NEXT: "TagType": "struct", // CHECK-NEXT: "Typedefs": [ // CHECK-NEXT: { +// CHECK-NEXT: "End": true, +// CHECK-NEXT: "InfoType": "typedef", // CHECK-NEXT: "IsUsing": false, // CHECK-NEXT: "Location": { // CHECK-NEXT: "Filename": "{{.*}}class.cpp", diff --git a/clang-tools-extra/test/clang-doc/json/compound-constraints.cpp b/clang-tools-extra/test/clang-doc/json/compound-constraints.cpp index 34acb68..bb2b4ca 100644 --- a/clang-tools-extra/test/clang-doc/json/compound-constraints.cpp +++ b/clang-tools-extra/test/clang-doc/json/compound-constraints.cpp @@ -37,6 +37,7 @@ template<typename T> requires (Incrementable<T> && Decrementable<T>) || PreIncre // CHECK-NEXT: "USR": "{{[0-9A-F]*}}" // CHECK-NEXT: }, // CHECK-NEXT: { +// CHECK-NEXT: "End": true, // CHECK-NEXT: "Expression": "Decrementable<T>", // CHECK-NEXT: "Name": "Decrementable", // CHECK-NEXT: "Path": "", @@ -55,6 +56,7 @@ template<typename T> requires (Incrementable<T> && Decrementable<T>) || PreIncre // CHECK-NEXT: "USR": "{{[0-9A-F]*}}" // CHECK-NEXT: }, // CHECK-NEXT: { +// CHECK-NEXT: "End": true, // CHECK-NEXT: "Expression": "Decrementable<T>", // CHECK-NEXT: "Name": "Decrementable", // CHECK-NEXT: "Path": "", @@ -87,6 +89,7 @@ template<typename T> requires (Incrementable<T> && Decrementable<T>) || PreIncre // CHECK-NEXT: "USR": "{{[0-9A-F]*}}" // CHECK-NEXT: }, // CHECK-NEXT: { +// CHECK-NEXT: "End": true, // CHECK-NEXT: "Expression": "PreDecrementable<T>", // CHECK-NEXT: "Name": "PreDecrementable", // CHECK-NEXT: "Path": "", @@ -112,6 +115,7 @@ template<typename T> requires (Incrementable<T> && Decrementable<T>) || PreIncre // CHECK-NEXT: "USR": "{{[0-9A-F]*}}" // CHECK-NEXT: }, // CHECK-NEXT: { +// CHECK-NEXT: "End": true, // CHECK-NEXT: "Expression": "PreIncrementable<T>", // CHECK-NEXT: "Name": "PreIncrementable", // CHECK-NEXT: "Path": "", diff --git a/clang-tools-extra/test/clang-doc/json/concept.cpp b/clang-tools-extra/test/clang-doc/json/concept.cpp index b946393..4c81024 100644 --- a/clang-tools-extra/test/clang-doc/json/concept.cpp +++ b/clang-tools-extra/test/clang-doc/json/concept.cpp @@ -13,16 +13,14 @@ concept Incrementable = requires(T x) { // CHECK-NEXT: "Concepts": [ // CHECK-NEXT: { // CHECK-NEXT: "ConstraintExpression": "requires (T x) { ++x; x++; }", -// CHECK-NEXT: "Description": [ -// CHECK-NEXT: { -// CHECK-NEXT: "FullComment": { -// CHECK-NEXT: "Children": [ -// CHECK-NEXT: { -// CHECK-NEXT: "ParagraphComment": { -// CHECK-NEXT: "Children": [ -// CHECK-NEXT: { -// CHECK-NEXT: "TextComment": " Requires that T suports post and pre-incrementing." -// CHECK: ], +// CHECK-NEXT: "Description": { +// CHECK-NEXT: "HasParagraphComments": true, +// CHECK-NEXT: "ParagraphComments": [ +// CHECK-NEXT: [ +// CHECK-NEXT: { +// CHECK-NEXT: "TextComment": " Requires that T suports post and pre-incrementing." +// CHECK: "End": true, +// CHECK-NEXT: "InfoType": "concept", // CHECK-NEXT: "IsType": true, // CHECK-NEXT: "Name": "Incrementable", // CHECK-NEXT: "Template": { diff --git a/clang-tools-extra/test/clang-doc/json/function-requires.cpp b/clang-tools-extra/test/clang-doc/json/function-requires.cpp index 08ac4c7..59ed39e 100644 --- a/clang-tools-extra/test/clang-doc/json/function-requires.cpp +++ b/clang-tools-extra/test/clang-doc/json/function-requires.cpp @@ -14,10 +14,12 @@ template<Incrementable T> Incrementable auto incrementTwo(T t); // CHECK: "Functions": [ // CHECK-NEXT: { +// CHECK-NEXT: "InfoType": "function", // CHECK-NEXT: "IsStatic": false, // CHECK-NEXT: "Name": "increment", // CHECK-NEXT: "Params": [ // CHECK-NEXT: { +// CHECK-NEXT: "End": true, // CHECK-NEXT: "Name": "t", // CHECK-NEXT: "Type": "T" // CHECK-NEXT: } @@ -32,6 +34,7 @@ template<Incrementable T> Incrementable auto incrementTwo(T t); // CHECK-NEXT: "Template": { // CHECK-NEXT: "Constraints": [ // CHECK-NEXT: { +// CHECK-NEXT: "End": true, // CHECK-NEXT: "Expression": "Incrementable<T>", // CHECK-NEXT: "Name": "Incrementable", // CHECK-NEXT: "Path": "", @@ -46,10 +49,13 @@ template<Incrementable T> Incrementable auto incrementTwo(T t); // CHECK-NEXT: "USR": "{{[0-9A-F]*}}" // CHECK-NEXT: }, // CHECK-NEXT: { +// CHECK-NEXT: "End": true, +// CHECK-NEXT: "InfoType": "function", // CHECK-NEXT: "IsStatic": false, // CHECK-NEXT: "Name": "incrementTwo", // CHECK-NEXT: "Params": [ // CHECK-NEXT: { +// CHECK-NEXT: "End": true, // CHECK-NEXT: "Name": "t", // CHECK-NEXT: "Type": "T" // CHECK-NEXT: } @@ -64,6 +70,7 @@ template<Incrementable T> Incrementable auto incrementTwo(T t); // CHECK-NEXT: "Template": { // CHECK-NEXT: "Constraints": [ // CHECK-NEXT: { +// CHECK-NEXT: "End": true, // CHECK-NEXT: "Expression": "Incrementable<T>", // CHECK-NEXT: "Name": "Incrementable", // CHECK-NEXT: "Path": "", diff --git a/clang-tools-extra/test/clang-doc/json/method-template.cpp b/clang-tools-extra/test/clang-doc/json/method-template.cpp index ac8450a..14232d0 100644 --- a/clang-tools-extra/test/clang-doc/json/method-template.cpp +++ b/clang-tools-extra/test/clang-doc/json/method-template.cpp @@ -9,6 +9,7 @@ struct MyClass { // CHECK: "PublicFunctions": [ // CHECK-NEXT: { +// CHECK-NEXT: "InfoType": "function", // CHECK-NEXT: "IsStatic": false, // CHECK-NEXT: "Location": { // CHECK-NEXT: "Filename": "{{.*}}method-template.cpp", @@ -21,6 +22,7 @@ struct MyClass { // CHECK-NEXT: ], // CHECK-NEXT: "Params": [ // CHECK-NEXT: { +// CHECK-NEXT: "End": true, // CHECK-NEXT: "Name": "param", // CHECK-NEXT: "Type": "T" // CHECK-NEXT: } diff --git a/clang-tools-extra/test/clang-doc/json/namespace.cpp b/clang-tools-extra/test/clang-doc/json/namespace.cpp index 779d7b49..4b6b388 100644 --- a/clang-tools-extra/test/clang-doc/json/namespace.cpp +++ b/clang-tools-extra/test/clang-doc/json/namespace.cpp @@ -20,8 +20,11 @@ enum Color { typedef int MyTypedef; // CHECK: { +// CHECK-NEXT: "DocumentationFileName": "index", // CHECK-NEXT: "Enums": [ // CHECK-NEXT: { +// CHECK-NEXT: "End": true, +// CHECK-NEXT: "InfoType": "enum", // CHECK-NEXT: "Location": { // CHECK-NEXT: "Filename": "{{.*}}namespace.cpp", // CHECK-NEXT: "LineNumber": 14 @@ -36,6 +39,7 @@ typedef int MyTypedef; // CHECK-NEXT: "Value": "1" // CHECK-NEXT: }, // CHECK-NEXT: { +// CHECK-NEXT: "End": true, // CHECK-NEXT: "Name": "BLUE", // CHECK-NEXT: "ValueExpr": "5" // CHECK-NEXT: } @@ -47,10 +51,13 @@ typedef int MyTypedef; // CHECK-NEXT: ], // CHECK-NEXT: "Functions": [ // CHECK-NEXT: { +// CHECK-NEXT: "End": true, +// CHECK-NEXT: "InfoType": "function", // CHECK-NEXT: "IsStatic": false, // CHECK-NEXT: "Name": "myFunction", // CHECK-NEXT: "Params": [ // CHECK-NEXT: { +// CHECK-NEXT: "End": true, // CHECK-NEXT: "Name": "Param", // CHECK-NEXT: "Type": "int" // CHECK-NEXT: } @@ -65,9 +72,13 @@ typedef int MyTypedef; // CHECK-NEXT: "USR": "{{[0-9A-F]*}}" // CHECK-NEXT: } // CHECK-NEXT: ], +// CHECK-NEXT: "HasEnums": true, +// CHECK-NEXT: "HasRecords": true, +// CHECK-NEXT: "InfoType": "namespace", // CHECK-NEXT: "Name": "", // CHECK-NEXT: "Namespaces": [ // CHECK-NEXT: { +// CHECK-NEXT: "End": true, // CHECK-NEXT: "Name": "NestedNamespace", // CHECK-NEXT: "Path": "", // CHECK-NEXT: "QualName": "NestedNamespace", @@ -76,6 +87,8 @@ typedef int MyTypedef; // CHECK-NEXT: ], // CHECK-NEXT: "Records": [ // CHECK-NEXT: { +// CHECK-NEXT: "DocumentationFileName": "_ZTV7MyClass", +// CHECK-NEXT: "End": true, // CHECK-NEXT: "Name": "MyClass", // CHECK-NEXT: "Path": "GlobalNamespace", // CHECK-NEXT: "QualName": "MyClass", @@ -84,6 +97,8 @@ typedef int MyTypedef; // CHECK-NEXT: ], // CHECK-NEXT: "Typedefs": [ // CHECK-NEXT: { +// CHECK-NEXT: "End": true, +// CHECK-NEXT: "InfoType": "typedef", // CHECK-NEXT: "IsUsing": false, // CHECK-NEXT: "Location": { // CHECK-NEXT: "Filename": "{{.*}}namespace.cpp", @@ -104,6 +119,8 @@ typedef int MyTypedef; // CHECK-NEXT: "USR": "0000000000000000000000000000000000000000" // CHECK-NEXT: "Variables": [ // CHECK-NEXT: { +// CHECK-NEXT: "End": true, +// CHECK-NEXT: "InfoType": "variable", // CHECK-NEXT: "IsStatic": true, // CHECK-NEXT: "Location": { // CHECK-NEXT: "Filename": "{{.*}}namespace.cpp", diff --git a/clang-tools-extra/test/clang-doc/json/nested-namespace.cpp b/clang-tools-extra/test/clang-doc/json/nested-namespace.cpp index 54f95c4..255e540 100644 --- a/clang-tools-extra/test/clang-doc/json/nested-namespace.cpp +++ b/clang-tools-extra/test/clang-doc/json/nested-namespace.cpp @@ -12,6 +12,8 @@ namespace nested { // NESTED: "Variables": [ // NESTED-NEXT: { +// NESTED-NEXT: "End": true, +// NESTED-NEXT: "InfoType": "variable", // NESTED-NEXT: "IsStatic": false, // NESTED-NEXT: "Location": { // NESTED-NEXT: "Filename": "{{.*}}nested-namespace.cpp", @@ -24,6 +26,8 @@ namespace nested { // INNER: "Variables": [ // INNER-NEXT: { +// INNER-NEXT: "End": true, +// INNER-NEXT: "InfoType": "variable", // INNER-NEXT: "IsStatic": false, // INNER-NEXT: "Location": { // INNER-NEXT: "Filename": "{{.*}}nested-namespace.cpp", diff --git a/clang-tools-extra/test/clang-doc/mustache-index.cpp b/clang-tools-extra/test/clang-doc/mustache-index.cpp index cad4cc8..910233b 100644 --- a/clang-tools-extra/test/clang-doc/mustache-index.cpp +++ b/clang-tools-extra/test/clang-doc/mustache-index.cpp @@ -1,6 +1,6 @@ // RUN: rm -rf %t && mkdir -p %t // RUN: clang-doc --format=mustache --output=%t --executor=standalone %s -// RUN: FileCheck %s < %t/GlobalNamespace/index.html +// RUN: FileCheck %s < %t/index.html enum Color { RED, @@ -15,7 +15,7 @@ class Foo; // CHECK-NEXT: </li> // CHECK-NEXT: <ul> // CHECK-NEXT: <li class="sidebar-item-container"> -// CHECK-NEXT: <a class="sidebar-item" href="#{{[0-9A-F]*}}">enum Color</a> +// CHECK-NEXT: <a class="sidebar-item" href="#{{[0-9A-F]*}}">Color</a> // CHECK-NEXT: </li> // CHECK-NEXT: </ul> // CHECK: <li class="sidebar-section"> @@ -69,7 +69,11 @@ class Foo; // CHECK-NEXT: <h2>Inner Classes</h2> // CHECK-NEXT: <ul class="class-container"> // CHECK-NEXT: <li id="{{[0-9A-F]*}}" style="max-height: 40px;"> -// CHECK-NEXT: <a href="Foo.html"><pre><code class="language-cpp code-clang-doc" >class Foo</code></pre></a> +// CHECK-NEXT: <a href="_ZTV3Foo.html"> +// CHECK-NEXT: <pre> +// CHECK-NEXT: <code class="language-cpp code-clang-doc">class Foo</code> +// CHECK-NEXT: </pre> +// CHECK-NEXT: </a> // CHECK-NEXT: </li> // CHECK-NEXT: </ul> // CHECK-NEXT: </section> diff --git a/clang-tools-extra/test/clang-doc/mustache-separate-namespace.cpp b/clang-tools-extra/test/clang-doc/mustache-separate-namespace.cpp index ec29b24..7d7d108 100644 --- a/clang-tools-extra/test/clang-doc/mustache-separate-namespace.cpp +++ b/clang-tools-extra/test/clang-doc/mustache-separate-namespace.cpp @@ -1,6 +1,6 @@ // RUN: rm -rf %t && mkdir -p %t // RUN: clang-doc --format=mustache --output=%t --executor=standalone %s -// RUN: FileCheck %s < %t/MyNamespace/index.html +// RUN: FileCheck %s < %t/MyNamespace.html namespace MyNamespace { class Foo; @@ -8,6 +8,10 @@ namespace MyNamespace { // CHECK: <ul class="class-container"> // CHECK-NEXT: <li id="{{[0-9A-F]*}}" style="max-height: 40px;"> -// CHECK-NEXT: <a href="Foo.html"><pre><code class="language-cpp code-clang-doc" >class Foo</code></pre></a> +// CHECK-NEXT: <a href="_ZTVN11MyNamespace3FooE.html"> +// CHECK-NEXT: <pre> +// CHECK-NEXT: <code class="language-cpp code-clang-doc">class Foo</code> +// CHECK-NEXT: </pre> +// CHECK-NEXT: </a> // CHECK-NEXT: </li> // CHECK-NEXT: </ul> diff --git a/clang-tools-extra/test/clang-include-fixer/include_path.cpp b/clang-tools-extra/test/clang-include-fixer/include_path.cpp index 9185b7a..a6f4a45 100644 --- a/clang-tools-extra/test/clang-include-fixer/include_path.cpp +++ b/clang-tools-extra/test/clang-include-fixer/include_path.cpp @@ -1,18 +1,18 @@ -// RUN: mkdir -p %T/clang-include-fixer/include -// RUN: mkdir -p %T/clang-include-fixer/symbols -// RUN: mkdir -p %T/clang-include-fixer/build -// RUN: mkdir -p %T/clang-include-fixer/src -// RUN: sed 's|test_dir|%/T/clang-include-fixer|g' %S/Inputs/database_template.json > %T/clang-include-fixer/build/compile_commands.json -// RUN: echo -e '#include "bar.h"\nb::a::bar f;' > %T/clang-include-fixer/src/bar.cpp -// RUN: echo 'namespace b { namespace a { class bar {}; } }' > %T/clang-include-fixer/include/bar.h -// RUN: cd %T/clang-include-fixer/build -// RUN: find-all-symbols -output-dir=%T/clang-include-fixer/symbols -p=. %T/clang-include-fixer/src/bar.cpp -// RUN: find-all-symbols -merge-dir=%T/clang-include-fixer/symbols %T/clang-include-fixer/build/find_all_symbols.yaml -// RUN: FileCheck -input-file=%T/clang-include-fixer/build/find_all_symbols.yaml -check-prefix=CHECK-YAML %s +// RUN: mkdir -p %t.dir/clang-include-fixer/include +// RUN: mkdir -p %t.dir/clang-include-fixer/symbols +// RUN: mkdir -p %t.dir/clang-include-fixer/build +// RUN: mkdir -p %t.dir/clang-include-fixer/src +// RUN: sed 's|test_dir|%/t.dir/clang-include-fixer|g' %S/Inputs/database_template.json > %t.dir/clang-include-fixer/build/compile_commands.json +// RUN: echo -e '#include "bar.h"\nb::a::bar f;' > %t.dir/clang-include-fixer/src/bar.cpp +// RUN: echo 'namespace b { namespace a { class bar {}; } }' > %t.dir/clang-include-fixer/include/bar.h +// RUN: cd %t.dir/clang-include-fixer/build +// RUN: find-all-symbols -output-dir=%t.dir/clang-include-fixer/symbols -p=. %t.dir/clang-include-fixer/src/bar.cpp +// RUN: find-all-symbols -merge-dir=%t.dir/clang-include-fixer/symbols %t.dir/clang-include-fixer/build/find_all_symbols.yaml +// RUN: FileCheck -input-file=%t.dir/clang-include-fixer/build/find_all_symbols.yaml -check-prefix=CHECK-YAML %s // -// RUN: echo 'b::a::bar f;' > %T/clang-include-fixer/src/bar.cpp -// RUN: clang-include-fixer -db=yaml -input=%T/clang-include-fixer/build/find_all_symbols.yaml -minimize-paths=true -p=. %T/clang-include-fixer/src/bar.cpp -// RUN: FileCheck -input-file=%T/clang-include-fixer/src/bar.cpp %s +// RUN: echo 'b::a::bar f;' > %t.dir/clang-include-fixer/src/bar.cpp +// RUN: clang-include-fixer -db=yaml -input=%t.dir/clang-include-fixer/build/find_all_symbols.yaml -minimize-paths=true -p=. %t.dir/clang-include-fixer/src/bar.cpp +// RUN: FileCheck -input-file=%t.dir/clang-include-fixer/src/bar.cpp %s // CHECK-YAML: ..{{[/\\]}}include{{[/\\]}}bar.h // CHECK: #include "bar.h" diff --git a/clang-tools-extra/test/clang-include-fixer/multiple_fixes.cpp b/clang-tools-extra/test/clang-include-fixer/multiple_fixes.cpp index 791417a..6c82e2a 100644 --- a/clang-tools-extra/test/clang-include-fixer/multiple_fixes.cpp +++ b/clang-tools-extra/test/clang-include-fixer/multiple_fixes.cpp @@ -1,11 +1,11 @@ // REQUIRES: shell // RUN: sed -e 's#//.*$##' %s > %t.cpp -// RUN: mkdir -p %T/clang-include-fixer/multiple-fixes -// RUN: echo 'foo f;' > %T/clang-include-fixer/multiple-fixes/foo.cpp -// RUN: echo 'bar b;' > %T/clang-include-fixer/multiple-fixes/bar.cpp -// RUN: clang-include-fixer -db=fixed -input='foo= "foo.h";bar= "bar.h"' %T/clang-include-fixer/multiple-fixes/*.cpp -- -// RUN: FileCheck -input-file=%T/clang-include-fixer/multiple-fixes/bar.cpp %s -check-prefix=CHECK-BAR -// RUN: FileCheck -input-file=%T/clang-include-fixer/multiple-fixes/foo.cpp %s -check-prefix=CHECK-FOO +// RUN: mkdir -p %t.dir/clang-include-fixer/multiple-fixes +// RUN: echo 'foo f;' > %t.dir/clang-include-fixer/multiple-fixes/foo.cpp +// RUN: echo 'bar b;' > %t.dir/clang-include-fixer/multiple-fixes/bar.cpp +// RUN: clang-include-fixer -db=fixed -input='foo= "foo.h";bar= "bar.h"' %t.dir/clang-include-fixer/multiple-fixes/*.cpp -- +// RUN: FileCheck -input-file=%t.dir/clang-include-fixer/multiple-fixes/bar.cpp %s -check-prefix=CHECK-BAR +// RUN: FileCheck -input-file=%t.dir/clang-include-fixer/multiple-fixes/foo.cpp %s -check-prefix=CHECK-FOO // // CHECK-FOO: #include "foo.h" // CHECK-FOO: foo f; diff --git a/clang-tools-extra/test/clang-include-fixer/yamldb_autodetect.cpp b/clang-tools-extra/test/clang-include-fixer/yamldb_autodetect.cpp index 1997390..1978e5d 100644 --- a/clang-tools-extra/test/clang-include-fixer/yamldb_autodetect.cpp +++ b/clang-tools-extra/test/clang-include-fixer/yamldb_autodetect.cpp @@ -1,6 +1,6 @@ -// RUN: mkdir -p %T/foo/bar -// RUN: cp %p/Inputs/fake_yaml_db.yaml %T/find_all_symbols_db.yaml -// RUN: cd %T/foo +// RUN: mkdir -p %t.dir/foo/bar +// RUN: cp %p/Inputs/fake_yaml_db.yaml %t.dir/find_all_symbols_db.yaml +// RUN: cd %t.dir/foo // RUN: sed -e 's#//.*$##' %s > bar/test.cpp // RUN: clang-include-fixer -db=yaml bar/test.cpp -- // RUN: FileCheck %s -input-file=bar/test.cpp diff --git a/clang-tools-extra/test/clang-move/move-class.cpp b/clang-tools-extra/test/clang-move/move-class.cpp index a30cb4d..5fb0258 100644 --- a/clang-tools-extra/test/clang-move/move-class.cpp +++ b/clang-tools-extra/test/clang-move/move-class.cpp @@ -1,25 +1,25 @@ -// RUN: mkdir -p %T/clang-move/build -// RUN: mkdir -p %T/clang-move/include -// RUN: mkdir -p %T/clang-move/src -// RUN: sed 's|$test_dir|%/T/clang-move|g' %S/Inputs/database_template.json > %T/clang-move/compile_commands.json -// RUN: cp %S/Inputs/test.h %T/clang-move/include -// RUN: cp %S/Inputs/test.cpp %T/clang-move/src -// RUN: touch %T/clang-move/include/test2.h -// RUN: cd %T/clang-move/build -// RUN: clang-move -names="a::Foo" -new_cc=%T/clang-move/new_test.cpp -new_header=%T/clang-move/new_test.h -old_cc=../src/test.cpp -old_header=../include/test.h %T/clang-move/src/test.cpp -// RUN: FileCheck -input-file=%T/clang-move/new_test.cpp -check-prefix=CHECK-NEW-TEST-CPP %s -// RUN: FileCheck -input-file=%T/clang-move/new_test.h -check-prefix=CHECK-NEW-TEST-H %s -// RUN: FileCheck -input-file=%T/clang-move/src/test.cpp -check-prefix=CHECK-OLD-TEST-EMPTY -allow-empty %s -// RUN: FileCheck -input-file=%T/clang-move/include/test.h -check-prefix=CHECK-OLD-TEST-EMPTY -allow-empty %s +// RUN: mkdir -p %t.dir/clang-move/build +// RUN: mkdir -p %t.dir/clang-move/include +// RUN: mkdir -p %t.dir/clang-move/src +// RUN: sed 's|$test_dir|%/t.dir/clang-move|g' %S/Inputs/database_template.json > %t.dir/clang-move/compile_commands.json +// RUN: cp %S/Inputs/test.h %t.dir/clang-move/include +// RUN: cp %S/Inputs/test.cpp %t.dir/clang-move/src +// RUN: touch %t.dir/clang-move/include/test2.h +// RUN: cd %t.dir/clang-move/build +// RUN: clang-move -names="a::Foo" -new_cc=%t.dir/clang-move/new_test.cpp -new_header=%t.dir/clang-move/new_test.h -old_cc=../src/test.cpp -old_header=../include/test.h %t.dir/clang-move/src/test.cpp +// RUN: FileCheck -input-file=%t.dir/clang-move/new_test.cpp -check-prefix=CHECK-NEW-TEST-CPP %s +// RUN: FileCheck -input-file=%t.dir/clang-move/new_test.h -check-prefix=CHECK-NEW-TEST-H %s +// RUN: FileCheck -input-file=%t.dir/clang-move/src/test.cpp -check-prefix=CHECK-OLD-TEST-EMPTY -allow-empty %s +// RUN: FileCheck -input-file=%t.dir/clang-move/include/test.h -check-prefix=CHECK-OLD-TEST-EMPTY -allow-empty %s // -// RUN: cp %S/Inputs/test.h %T/clang-move/include -// RUN: cp %S/Inputs/test.cpp %T/clang-move/src -// RUN: cd %T/clang-move/build -// RUN: clang-move -names="a::Foo" -new_cc=%T/clang-move/new_test.cpp -new_header=%T/clang-move/new_test.h -old_cc=%T/clang-move/src/test.cpp -old_header=%T/clang-move/include/test.h %T/clang-move/src/test.cpp -// RUN: FileCheck -input-file=%T/clang-move/new_test.cpp -check-prefix=CHECK-NEW-TEST-CPP %s -// RUN: FileCheck -input-file=%T/clang-move/new_test.h -check-prefix=CHECK-NEW-TEST-H %s -// RUN: FileCheck -input-file=%T/clang-move/src/test.cpp -check-prefix=CHECK-OLD-TEST-EMPTY -allow-empty %s -// RUN: FileCheck -input-file=%T/clang-move/include/test.h -check-prefix=CHECK-OLD-TEST-EMPTY -allow-empty %s +// RUN: cp %S/Inputs/test.h %t.dir/clang-move/include +// RUN: cp %S/Inputs/test.cpp %t.dir/clang-move/src +// RUN: cd %t.dir/clang-move/build +// RUN: clang-move -names="a::Foo" -new_cc=%t.dir/clang-move/new_test.cpp -new_header=%t.dir/clang-move/new_test.h -old_cc=%t.dir/clang-move/src/test.cpp -old_header=%t.dir/clang-move/include/test.h %t.dir/clang-move/src/test.cpp +// RUN: FileCheck -input-file=%t.dir/clang-move/new_test.cpp -check-prefix=CHECK-NEW-TEST-CPP %s +// RUN: FileCheck -input-file=%t.dir/clang-move/new_test.h -check-prefix=CHECK-NEW-TEST-H %s +// RUN: FileCheck -input-file=%t.dir/clang-move/src/test.cpp -check-prefix=CHECK-OLD-TEST-EMPTY -allow-empty %s +// RUN: FileCheck -input-file=%t.dir/clang-move/include/test.h -check-prefix=CHECK-OLD-TEST-EMPTY -allow-empty %s // // // CHECK-NEW-TEST-H: #ifndef TEST_H // comment 1 diff --git a/clang-tools-extra/test/clang-move/move-enum-decl.cpp b/clang-tools-extra/test/clang-move/move-enum-decl.cpp index 42f6f99..f8fb5f6 100644 --- a/clang-tools-extra/test/clang-move/move-enum-decl.cpp +++ b/clang-tools-extra/test/clang-move/move-enum-decl.cpp @@ -1,14 +1,14 @@ -// RUN: mkdir -p %T/move-enum -// RUN: cp %S/Inputs/enum.h %T/move-enum/enum.h -// RUN: echo '#include "enum.h"' > %T/move-enum/enum.cpp -// RUN: cd %T/move-enum +// RUN: mkdir -p %t.dir/move-enum +// RUN: cp %S/Inputs/enum.h %t.dir/move-enum/enum.h +// RUN: echo '#include "enum.h"' > %t.dir/move-enum/enum.cpp +// RUN: cd %t.dir/move-enum // // ----------------------------------------------------------------------------- // Test moving enum declarations. // ----------------------------------------------------------------------------- -// RUN: clang-move -names="a::E1" -new_cc=%T/move-enum/new_test.cpp -new_header=%T/move-enum/new_test.h -old_cc=%T/move-enum/enum.cpp -old_header=%T/move-enum/enum.h %T/move-enum/enum.cpp -- -std=c++11 -// RUN: FileCheck -input-file=%T/move-enum/new_test.h -check-prefix=CHECK-NEW-TEST-H-CASE1 %s -// RUN: FileCheck -input-file=%T/move-enum/enum.h -check-prefix=CHECK-OLD-TEST-H-CASE1 %s +// RUN: clang-move -names="a::E1" -new_cc=%t.dir/move-enum/new_test.cpp -new_header=%t.dir/move-enum/new_test.h -old_cc=%t.dir/move-enum/enum.cpp -old_header=%t.dir/move-enum/enum.h %t.dir/move-enum/enum.cpp -- -std=c++11 +// RUN: FileCheck -input-file=%t.dir/move-enum/new_test.h -check-prefix=CHECK-NEW-TEST-H-CASE1 %s +// RUN: FileCheck -input-file=%t.dir/move-enum/enum.h -check-prefix=CHECK-OLD-TEST-H-CASE1 %s // // CHECK-NEW-TEST-H-CASE1: namespace a { // CHECK-NEW-TEST-H-CASE1-NEXT: enum E1 { Green, Red }; @@ -20,11 +20,11 @@ // ----------------------------------------------------------------------------- // Test moving scoped enum declarations. // ----------------------------------------------------------------------------- -// RUN: cp %S/Inputs/enum.h %T/move-enum/enum.h -// RUN: echo '#include "enum.h"' > %T/move-enum/enum.cpp -// RUN: clang-move -names="a::E2" -new_cc=%T/move-enum/new_test.cpp -new_header=%T/move-enum/new_test.h -old_cc=%T/move-enum/enum.cpp -old_header=%T/move-enum/enum.h %T/move-enum/enum.cpp -- -std=c++11 -// RUN: FileCheck -input-file=%T/move-enum/new_test.h -check-prefix=CHECK-NEW-TEST-H-CASE2 %s -// RUN: FileCheck -input-file=%T/move-enum/enum.h -check-prefix=CHECK-OLD-TEST-H-CASE2 %s +// RUN: cp %S/Inputs/enum.h %t.dir/move-enum/enum.h +// RUN: echo '#include "enum.h"' > %t.dir/move-enum/enum.cpp +// RUN: clang-move -names="a::E2" -new_cc=%t.dir/move-enum/new_test.cpp -new_header=%t.dir/move-enum/new_test.h -old_cc=%t.dir/move-enum/enum.cpp -old_header=%t.dir/move-enum/enum.h %t.dir/move-enum/enum.cpp -- -std=c++11 +// RUN: FileCheck -input-file=%t.dir/move-enum/new_test.h -check-prefix=CHECK-NEW-TEST-H-CASE2 %s +// RUN: FileCheck -input-file=%t.dir/move-enum/enum.h -check-prefix=CHECK-OLD-TEST-H-CASE2 %s // CHECK-NEW-TEST-H-CASE2: namespace a { // CHECK-NEW-TEST-H-CASE2-NEXT: enum class E2 { Yellow }; @@ -36,9 +36,9 @@ // ----------------------------------------------------------------------------- // Test not moving class-insided enum declarations. // ----------------------------------------------------------------------------- -// RUN: cp %S/Inputs/enum.h %T/move-enum/enum.h -// RUN: echo '#include "enum.h"' > %T/move-enum/enum.cpp -// RUN: clang-move -names="a::C::E3" -new_cc=%T/move-enum/new_test.cpp -new_header=%T/move-enum/new_test.h -old_cc=%T/move-enum/enum.cpp -old_header=%T/move-enum/enum.h %T/move-enum/enum.cpp -- -std=c++11 -// RUN: FileCheck -input-file=%T/move-enum/new_test.h -allow-empty -check-prefix=CHECK-EMPTY %s +// RUN: cp %S/Inputs/enum.h %t.dir/move-enum/enum.h +// RUN: echo '#include "enum.h"' > %t.dir/move-enum/enum.cpp +// RUN: clang-move -names="a::C::E3" -new_cc=%t.dir/move-enum/new_test.cpp -new_header=%t.dir/move-enum/new_test.h -old_cc=%t.dir/move-enum/enum.cpp -old_header=%t.dir/move-enum/enum.h %t.dir/move-enum/enum.cpp -- -std=c++11 +// RUN: FileCheck -input-file=%t.dir/move-enum/new_test.h -allow-empty -check-prefix=CHECK-EMPTY %s // CHECK-EMPTY: {{^}}{{$}} diff --git a/clang-tools-extra/test/clang-move/move-function.cpp b/clang-tools-extra/test/clang-move/move-function.cpp index 0324b80..a52d55c 100644 --- a/clang-tools-extra/test/clang-move/move-function.cpp +++ b/clang-tools-extra/test/clang-move/move-function.cpp @@ -1,9 +1,9 @@ -// RUN: mkdir -p %T/move-function -// RUN: cat %S/Inputs/function_test.h > %T/move-function/function_test.h -// RUN: cat %S/Inputs/function_test.cpp > %T/move-function/function_test.cpp -// RUN: cd %T/move-function -// RUN: clang-move -names="g" -new_header=%T/move-function/new_function_test.h -old_header=../move-function/function_test.h %T/move-function/function_test.cpp -- -// RUN: FileCheck -input-file=%T/move-function/new_function_test.h -check-prefix=CHECK-NEW-TEST-H-CASE1 %s +// RUN: mkdir -p %t.dir/move-function +// RUN: cat %S/Inputs/function_test.h > %t.dir/move-function/function_test.h +// RUN: cat %S/Inputs/function_test.cpp > %t.dir/move-function/function_test.cpp +// RUN: cd %t.dir/move-function +// RUN: clang-move -names="g" -new_header=%t.dir/move-function/new_function_test.h -old_header=../move-function/function_test.h %t.dir/move-function/function_test.cpp -- +// RUN: FileCheck -input-file=%t.dir/move-function/new_function_test.h -check-prefix=CHECK-NEW-TEST-H-CASE1 %s // // CHECK-NEW-TEST-H-CASE1: #ifndef {{.*}}NEW_FUNCTION_TEST_H // CHECK-NEW-TEST-H-CASE1: #define {{.*}}NEW_FUNCTION_TEST_H @@ -12,9 +12,9 @@ // CHECK-NEW-TEST-H-CASE1: {{[[:space:]]+}} // CHECK-NEW-TEST-H-CASE1: #endif // {{.*}}NEW_FUNCTION_TEST_H // -// RUN: cp %S/Inputs/function_test* %T/move-function -// RUN: clang-move -names="h" -new_header=%T/move-function/new_function_test.h -old_header=../move-function/function_test.h %T/move-function/function_test.cpp -- -// RUN: FileCheck -input-file=%T/move-function/new_function_test.h -check-prefix=CHECK-NEW-TEST-H-CASE2 %s +// RUN: cp %S/Inputs/function_test* %t.dir/move-function +// RUN: clang-move -names="h" -new_header=%t.dir/move-function/new_function_test.h -old_header=../move-function/function_test.h %t.dir/move-function/function_test.cpp -- +// RUN: FileCheck -input-file=%t.dir/move-function/new_function_test.h -check-prefix=CHECK-NEW-TEST-H-CASE2 %s // // CHECK-NEW-TEST-H-CASE2: #ifndef {{.*}}NEW_FUNCTION_TEST_H // CHECK-NEW-TEST-H-CASE2: #define {{.*}}NEW_FUNCTION_TEST_H @@ -25,10 +25,10 @@ // CHECK-NEW-TEST-H-CASE2: {{[[:space:]]+}} // CHECK-NEW-TEST-H-CASE2: #endif // {{.*}}NEW_FUNCTION_TEST_H // -// RUN: cp %S/Inputs/function_test* %T/move-function -// RUN: clang-move -names="f" -new_header=%T/move-function/new_function_test.h -new_cc=%T/move-function/new_function_test.cpp -old_header=../move-function/function_test.h -old_cc=../move-function/function_test.cpp %T/move-function/function_test.cpp -- -// RUN: FileCheck -input-file=%T/move-function/new_function_test.h -check-prefix=CHECK-NEW-TEST-H-CASE3 %s -// RUN: FileCheck -input-file=%T/move-function/new_function_test.cpp -check-prefix=CHECK-NEW-TEST-CPP-CASE3 %s +// RUN: cp %S/Inputs/function_test* %t.dir/move-function +// RUN: clang-move -names="f" -new_header=%t.dir/move-function/new_function_test.h -new_cc=%t.dir/move-function/new_function_test.cpp -old_header=../move-function/function_test.h -old_cc=../move-function/function_test.cpp %t.dir/move-function/function_test.cpp -- +// RUN: FileCheck -input-file=%t.dir/move-function/new_function_test.h -check-prefix=CHECK-NEW-TEST-H-CASE3 %s +// RUN: FileCheck -input-file=%t.dir/move-function/new_function_test.cpp -check-prefix=CHECK-NEW-TEST-CPP-CASE3 %s // // CHECK-NEW-TEST-H-CASE3: #ifndef {{.*}}NEW_FUNCTION_TEST_H // CHECK-NEW-TEST-H-CASE3: #define {{.*}}NEW_FUNCTION_TEST_H @@ -40,17 +40,17 @@ // CHECK-NEW-TEST-CPP-CASE3: {{[[:space:]]+}} // CHECK-NEW-TEST-CPP-CASE3: void f() {} // -// RUN: cat %S/Inputs/function_test.h > %T/move-function/function_test.h -// RUN: cat %S/Inputs/function_test.cpp > %T/move-function/function_test.cpp -// RUN: clang-move -names="A::f" -new_header=%T/move-function/new_function_test.h -new_cc=%T/move-function/new_function_test.cpp -old_header=../move-function/function_test.h -old_cc=../move-function/function_test.cpp %T/move-function/function_test.cpp -dump_result -- | FileCheck %s -check-prefix=CHECK-EMPTY +// RUN: cat %S/Inputs/function_test.h > %t.dir/move-function/function_test.h +// RUN: cat %S/Inputs/function_test.cpp > %t.dir/move-function/function_test.cpp +// RUN: clang-move -names="A::f" -new_header=%t.dir/move-function/new_function_test.h -new_cc=%t.dir/move-function/new_function_test.cpp -old_header=../move-function/function_test.h -old_cc=../move-function/function_test.cpp %t.dir/move-function/function_test.cpp -dump_result -- | FileCheck %s -check-prefix=CHECK-EMPTY // // CHECK-EMPTY: [{{[[:space:]]*}}] // -// RUN: cat %S/Inputs/function_test.h > %T/move-function/function_test.h -// RUN: cat %S/Inputs/function_test.cpp > %T/move-function/function_test.cpp -// RUN: clang-move -names="f,A" -new_header=%T/move-function/new_function_test.h -new_cc=%T/move-function/new_function_test.cpp -old_header=../move-function/function_test.h -old_cc=../move-function/function_test.cpp %T/move-function/function_test.cpp -- -// RUN: FileCheck -input-file=%T/move-function/new_function_test.h -check-prefix=CHECK-NEW-TEST-H-CASE4 %s -// RUN: FileCheck -input-file=%T/move-function/new_function_test.cpp -check-prefix=CHECK-NEW-TEST-CPP-CASE4 %s +// RUN: cat %S/Inputs/function_test.h > %t.dir/move-function/function_test.h +// RUN: cat %S/Inputs/function_test.cpp > %t.dir/move-function/function_test.cpp +// RUN: clang-move -names="f,A" -new_header=%t.dir/move-function/new_function_test.h -new_cc=%t.dir/move-function/new_function_test.cpp -old_header=../move-function/function_test.h -old_cc=../move-function/function_test.cpp %t.dir/move-function/function_test.cpp -- +// RUN: FileCheck -input-file=%t.dir/move-function/new_function_test.h -check-prefix=CHECK-NEW-TEST-H-CASE4 %s +// RUN: FileCheck -input-file=%t.dir/move-function/new_function_test.cpp -check-prefix=CHECK-NEW-TEST-CPP-CASE4 %s // CHECK-NEW-TEST-H-CASE4: #ifndef {{.*}}NEW_FUNCTION_TEST_H // CHECK-NEW-TEST-H-CASE4: #define {{.*}}NEW_FUNCTION_TEST_H diff --git a/clang-tools-extra/test/clang-move/move-multiple-classes.cpp b/clang-tools-extra/test/clang-move/move-multiple-classes.cpp index 821d567..513b904 100644 --- a/clang-tools-extra/test/clang-move/move-multiple-classes.cpp +++ b/clang-tools-extra/test/clang-move/move-multiple-classes.cpp @@ -1,12 +1,12 @@ -// RUN: mkdir -p %T/move-multiple-classes -// RUN: cp %S/Inputs/multiple_class_test* %T/move-multiple-classes/ -// RUN: cd %T/move-multiple-classes -// RUN: clang-move -names="c::EnclosingMove5::Nested" -new_cc=%T/move-multiple-classes/new_multiple_class_test.cpp -new_header=%T/move-multiple-classes/new_multiple_class_test.h -old_cc=%T/move-multiple-classes/multiple_class_test.cpp -old_header=../move-multiple-classes/multiple_class_test.h -dump_result %T/move-multiple-classes/multiple_class_test.cpp -- -std=c++11| FileCheck %s -check-prefix=CHECK-EMPTY -// RUN: clang-move -names="a::Move1, b::Move2,c::Move3,c::Move4,c::EnclosingMove5" -new_cc=%T/move-multiple-classes/new_multiple_class_test.cpp -new_header=%T/move-multiple-classes/new_multiple_class_test.h -old_cc=%T/move-multiple-classes/multiple_class_test.cpp -old_header=../move-multiple-classes/multiple_class_test.h %T/move-multiple-classes/multiple_class_test.cpp -- -std=c++11 -// RUN: FileCheck -input-file=%T/move-multiple-classes/new_multiple_class_test.cpp -check-prefix=CHECK-NEW-TEST-CPP %s -// RUN: FileCheck -input-file=%T/move-multiple-classes/new_multiple_class_test.h -check-prefix=CHECK-NEW-TEST-H %s -// RUN: FileCheck -input-file=%T/move-multiple-classes/multiple_class_test.cpp -check-prefix=CHECK-OLD-TEST-CPP %s -// RUN: FileCheck -input-file=%T/move-multiple-classes/multiple_class_test.h -check-prefix=CHECK-OLD-TEST-H %s +// RUN: mkdir -p %t.dir/move-multiple-classes +// RUN: cp %S/Inputs/multiple_class_test* %t.dir/move-multiple-classes/ +// RUN: cd %t.dir/move-multiple-classes +// RUN: clang-move -names="c::EnclosingMove5::Nested" -new_cc=%t.dir/move-multiple-classes/new_multiple_class_test.cpp -new_header=%t.dir/move-multiple-classes/new_multiple_class_test.h -old_cc=%t.dir/move-multiple-classes/multiple_class_test.cpp -old_header=../move-multiple-classes/multiple_class_test.h -dump_result %t.dir/move-multiple-classes/multiple_class_test.cpp -- -std=c++11| FileCheck %s -check-prefix=CHECK-EMPTY +// RUN: clang-move -names="a::Move1, b::Move2,c::Move3,c::Move4,c::EnclosingMove5" -new_cc=%t.dir/move-multiple-classes/new_multiple_class_test.cpp -new_header=%t.dir/move-multiple-classes/new_multiple_class_test.h -old_cc=%t.dir/move-multiple-classes/multiple_class_test.cpp -old_header=../move-multiple-classes/multiple_class_test.h %t.dir/move-multiple-classes/multiple_class_test.cpp -- -std=c++11 +// RUN: FileCheck -input-file=%t.dir/move-multiple-classes/new_multiple_class_test.cpp -check-prefix=CHECK-NEW-TEST-CPP %s +// RUN: FileCheck -input-file=%t.dir/move-multiple-classes/new_multiple_class_test.h -check-prefix=CHECK-NEW-TEST-H %s +// RUN: FileCheck -input-file=%t.dir/move-multiple-classes/multiple_class_test.cpp -check-prefix=CHECK-OLD-TEST-CPP %s +// RUN: FileCheck -input-file=%t.dir/move-multiple-classes/multiple_class_test.h -check-prefix=CHECK-OLD-TEST-H %s // // CHECK-EMPTY: [{{[[:space:]]*}}] // diff --git a/clang-tools-extra/test/clang-move/move-template-class.cpp b/clang-tools-extra/test/clang-move/move-template-class.cpp index 1a6a60b..29ed65e 100644 --- a/clang-tools-extra/test/clang-move/move-template-class.cpp +++ b/clang-tools-extra/test/clang-move/move-template-class.cpp @@ -1,18 +1,18 @@ -// RUN: mkdir -p %T/move-template-class -// RUN: cp %S/Inputs/template_class_test* %T/move-template-class -// RUN: cd %T/move-template-class -// RUN: clang-move -names="A,B" -new_cc=%T/move-template-class/new_template_class_test.cpp -new_header=%T/move-template-class/new_template_class_test.h -old_cc=%T/move-template-class/template_class_test.cpp -old_header=../move-template-class/template_class_test.h %T/move-template-class/template_class_test.cpp -- -// RUN: FileCheck -input-file=%T/move-template-class/template_class_test.cpp -check-prefix=CHECK-OLD-TEST-EMPTY -allow-empty %s -// RUN: FileCheck -input-file=%T/move-template-class/template_class_test.h -check-prefix=CHECK-OLD-TEST-EMPTY -allow-empty %s -// RUN: FileCheck -input-file=%T/move-template-class/new_template_class_test.cpp -check-prefix=CHECK-NEW-TEST-CPP-CASE1 %s -// RUN: FileCheck -input-file=%T/move-template-class/new_template_class_test.h -check-prefix=CHECK-NEW-TEST-H-CASE1 %s +// RUN: mkdir -p %t.dir/move-template-class +// RUN: cp %S/Inputs/template_class_test* %t.dir/move-template-class +// RUN: cd %t.dir/move-template-class +// RUN: clang-move -names="A,B" -new_cc=%t.dir/move-template-class/new_template_class_test.cpp -new_header=%t.dir/move-template-class/new_template_class_test.h -old_cc=%t.dir/move-template-class/template_class_test.cpp -old_header=../move-template-class/template_class_test.h %t.dir/move-template-class/template_class_test.cpp -- +// RUN: FileCheck -input-file=%t.dir/move-template-class/template_class_test.cpp -check-prefix=CHECK-OLD-TEST-EMPTY -allow-empty %s +// RUN: FileCheck -input-file=%t.dir/move-template-class/template_class_test.h -check-prefix=CHECK-OLD-TEST-EMPTY -allow-empty %s +// RUN: FileCheck -input-file=%t.dir/move-template-class/new_template_class_test.cpp -check-prefix=CHECK-NEW-TEST-CPP-CASE1 %s +// RUN: FileCheck -input-file=%t.dir/move-template-class/new_template_class_test.h -check-prefix=CHECK-NEW-TEST-H-CASE1 %s // -// RUN: cp %S/Inputs/template_class_test* %T/move-template-class -// RUN: clang-move -names="A" -new_cc=%T/move-template-class/new_template_class_test.cpp -new_header=%T/move-template-class/new_template_class_test.h -old_cc=%T/move-template-class/template_class_test.cpp -old_header=../move-template-class/template_class_test.h %T/move-template-class/template_class_test.cpp -- -// RUN: FileCheck -input-file=%T/move-template-class/template_class_test.h -check-prefix=CHECK-OLD-TEST-H-CASE2 %s -// RUN: FileCheck -input-file=%T/move-template-class/template_class_test.cpp -check-prefix=CHECK-OLD-TEST-CPP-CASE2 %s -// RUN: FileCheck -input-file=%T/move-template-class/new_template_class_test.h -check-prefix=CHECK-NEW-TEST-H-CASE2 %s -// RUN: FileCheck -input-file=%T/move-template-class/new_template_class_test.cpp -check-prefix=CHECK-NEW-TEST-CPP-CASE2 %s +// RUN: cp %S/Inputs/template_class_test* %t.dir/move-template-class +// RUN: clang-move -names="A" -new_cc=%t.dir/move-template-class/new_template_class_test.cpp -new_header=%t.dir/move-template-class/new_template_class_test.h -old_cc=%t.dir/move-template-class/template_class_test.cpp -old_header=../move-template-class/template_class_test.h %t.dir/move-template-class/template_class_test.cpp -- +// RUN: FileCheck -input-file=%t.dir/move-template-class/template_class_test.h -check-prefix=CHECK-OLD-TEST-H-CASE2 %s +// RUN: FileCheck -input-file=%t.dir/move-template-class/template_class_test.cpp -check-prefix=CHECK-OLD-TEST-CPP-CASE2 %s +// RUN: FileCheck -input-file=%t.dir/move-template-class/new_template_class_test.h -check-prefix=CHECK-NEW-TEST-H-CASE2 %s +// RUN: FileCheck -input-file=%t.dir/move-template-class/new_template_class_test.cpp -check-prefix=CHECK-NEW-TEST-CPP-CASE2 %s // // // CHECK-OLD-TEST-EMPTY: {{^}}{{$}} diff --git a/clang-tools-extra/test/clang-move/move-type-alias.cpp b/clang-tools-extra/test/clang-move/move-type-alias.cpp index ab70237..54d2b0e 100644 --- a/clang-tools-extra/test/clang-move/move-type-alias.cpp +++ b/clang-tools-extra/test/clang-move/move-type-alias.cpp @@ -1,14 +1,14 @@ -// RUN: mkdir -p %T/move-type-alias -// RUN: cp %S/Inputs/type_alias.h %T/move-type-alias/type_alias.h -// RUN: echo '#include "type_alias.h"' > %T/move-type-alias/type_alias.cpp -// RUN: cd %T/move-type-alias +// RUN: mkdir -p %t.dir/move-type-alias +// RUN: cp %S/Inputs/type_alias.h %t.dir/move-type-alias/type_alias.h +// RUN: echo '#include "type_alias.h"' > %t.dir/move-type-alias/type_alias.cpp +// RUN: cd %t.dir/move-type-alias // // ----------------------------------------------------------------------------- // Test moving typedef declarations. // ----------------------------------------------------------------------------- -// RUN: clang-move -names="Int1" -new_cc=%T/move-type-alias/new_test.cpp -new_header=%T/move-type-alias/new_test.h -old_cc=%T/move-type-alias/type_alias.cpp -old_header=%T/move-type-alias/type_alias.h %T/move-type-alias/type_alias.cpp -- -std=c++11 -// RUN: FileCheck -input-file=%T/move-type-alias/new_test.h -check-prefix=CHECK-NEW-TEST-H-CASE1 %s -// RUN: FileCheck -input-file=%T/move-type-alias/type_alias.h -check-prefix=CHECK-OLD-TEST-H-CASE1 %s +// RUN: clang-move -names="Int1" -new_cc=%t.dir/move-type-alias/new_test.cpp -new_header=%t.dir/move-type-alias/new_test.h -old_cc=%t.dir/move-type-alias/type_alias.cpp -old_header=%t.dir/move-type-alias/type_alias.h %t.dir/move-type-alias/type_alias.cpp -- -std=c++11 +// RUN: FileCheck -input-file=%t.dir/move-type-alias/new_test.h -check-prefix=CHECK-NEW-TEST-H-CASE1 %s +// RUN: FileCheck -input-file=%t.dir/move-type-alias/type_alias.h -check-prefix=CHECK-OLD-TEST-H-CASE1 %s // CHECK-NEW-TEST-H-CASE1: typedef int Int1; @@ -18,11 +18,11 @@ // ----------------------------------------------------------------------------- // Test moving type alias declarations. // ----------------------------------------------------------------------------- -// RUN: cp %S/Inputs/type_alias.h %T/move-type-alias/type_alias.h -// RUN: echo '#include "type_alias.h"' > %T/move-type-alias/type_alias.cpp -// RUN: clang-move -names="Int2" -new_cc=%T/move-type-alias/new_test.cpp -new_header=%T/move-type-alias/new_test.h -old_cc=%T/move-type-alias/type_alias.cpp -old_header=%T/move-type-alias/type_alias.h %T/move-type-alias/type_alias.cpp -- -std=c++11 -// RUN: FileCheck -input-file=%T/move-type-alias/new_test.h -check-prefix=CHECK-NEW-TEST-H-CASE2 %s -// RUN: FileCheck -input-file=%T/move-type-alias/type_alias.h -check-prefix=CHECK-OLD-TEST-H-CASE2 %s +// RUN: cp %S/Inputs/type_alias.h %t.dir/move-type-alias/type_alias.h +// RUN: echo '#include "type_alias.h"' > %t.dir/move-type-alias/type_alias.cpp +// RUN: clang-move -names="Int2" -new_cc=%t.dir/move-type-alias/new_test.cpp -new_header=%t.dir/move-type-alias/new_test.h -old_cc=%t.dir/move-type-alias/type_alias.cpp -old_header=%t.dir/move-type-alias/type_alias.h %t.dir/move-type-alias/type_alias.cpp -- -std=c++11 +// RUN: FileCheck -input-file=%t.dir/move-type-alias/new_test.h -check-prefix=CHECK-NEW-TEST-H-CASE2 %s +// RUN: FileCheck -input-file=%t.dir/move-type-alias/type_alias.h -check-prefix=CHECK-OLD-TEST-H-CASE2 %s // CHECK-NEW-TEST-H-CASE2: using Int2 = int; @@ -32,10 +32,10 @@ // ----------------------------------------------------------------------------- // Test moving template type alias declarations. // ----------------------------------------------------------------------------- -// RUN: cp %S/Inputs/type_alias.h %T/move-type-alias/type_alias.h -// RUN: echo '#include "type_alias.h"' > %T/move-type-alias/type_alias.cpp -// RUN: clang-move -names="B" -new_cc=%T/move-type-alias/new_test.cpp -new_header=%T/move-type-alias/new_test.h -old_cc=%T/move-type-alias/type_alias.cpp -old_header=%T/move-type-alias/type_alias.h %T/move-type-alias/type_alias.cpp -- -std=c++11 -// RUN: FileCheck -input-file=%T/move-type-alias/new_test.h -check-prefix=CHECK-OLD-TEST-H-CASE3 %s +// RUN: cp %S/Inputs/type_alias.h %t.dir/move-type-alias/type_alias.h +// RUN: echo '#include "type_alias.h"' > %t.dir/move-type-alias/type_alias.cpp +// RUN: clang-move -names="B" -new_cc=%t.dir/move-type-alias/new_test.cpp -new_header=%t.dir/move-type-alias/new_test.h -old_cc=%t.dir/move-type-alias/type_alias.cpp -old_header=%t.dir/move-type-alias/type_alias.h %t.dir/move-type-alias/type_alias.cpp -- -std=c++11 +// RUN: FileCheck -input-file=%t.dir/move-type-alias/new_test.h -check-prefix=CHECK-OLD-TEST-H-CASE3 %s // CHECK-NEW-TEST-H-CASE3: template<class T> using B = A<T>; // CHECK-OLD-TEST-H-CASE3-NOT: template<class T> using B = A<T>; @@ -44,9 +44,9 @@ // ----------------------------------------------------------------------------- // Test not moving class-insided typedef declarations. // ----------------------------------------------------------------------------- -// RUN: cp %S/Inputs/type_alias.h %T/move-type-alias/type_alias.h -// RUN: echo '#include "type_alias.h"' > %T/move-type-alias/type_alias.cpp -// RUN: clang-move -names="C::Int3" -new_cc=%T/move-type-alias/new_test.cpp -new_header=%T/move-type-alias/new_test.h -old_cc=%T/move-type-alias/type_alias.cpp -old_header=%T/move-type-alias/type_alias.h %T/move-type-alias/type_alias.cpp -- -std=c++11 -// RUN: FileCheck -input-file=%T/move-type-alias/new_test.h -allow-empty -check-prefix=CHECK-EMPTY %s +// RUN: cp %S/Inputs/type_alias.h %t.dir/move-type-alias/type_alias.h +// RUN: echo '#include "type_alias.h"' > %t.dir/move-type-alias/type_alias.cpp +// RUN: clang-move -names="C::Int3" -new_cc=%t.dir/move-type-alias/new_test.cpp -new_header=%t.dir/move-type-alias/new_test.h -old_cc=%t.dir/move-type-alias/type_alias.cpp -old_header=%t.dir/move-type-alias/type_alias.h %t.dir/move-type-alias/type_alias.cpp -- -std=c++11 +// RUN: FileCheck -input-file=%t.dir/move-type-alias/new_test.h -allow-empty -check-prefix=CHECK-EMPTY %s // CHECK-EMPTY: {{^}}{{$}} diff --git a/clang-tools-extra/test/clang-move/move-used-helper-decls.cpp b/clang-tools-extra/test/clang-move/move-used-helper-decls.cpp index b4aed2c..3092976 100644 --- a/clang-tools-extra/test/clang-move/move-used-helper-decls.cpp +++ b/clang-tools-extra/test/clang-move/move-used-helper-decls.cpp @@ -1,13 +1,13 @@ -// RUN: mkdir -p %T/used-helper-decls -// RUN: cp %S/Inputs/helper_decls_test* %T/used-helper-decls/ -// RUN: cd %T/used-helper-decls +// RUN: mkdir -p %t.dir/used-helper-decls +// RUN: cp %S/Inputs/helper_decls_test* %t.dir/used-helper-decls/ +// RUN: cd %t.dir/used-helper-decls // ---------------------------------------------------------------------------- // Test moving used helper function and its transitively used functions. // ---------------------------------------------------------------------------- -// RUN: clang-move -names="a::Class1" -new_cc=%T/used-helper-decls/new_helper_decls_test.cpp -new_header=%T/used-helper-decls/new_helper_decls_test.h -old_cc=%T/used-helper-decls/helper_decls_test.cpp -old_header=../used-helper-decls/helper_decls_test.h %T/used-helper-decls/helper_decls_test.cpp -- -std=c++11 -// RUN: FileCheck -input-file=%T/used-helper-decls/new_helper_decls_test.cpp -check-prefix=CHECK-NEW-CLASS1-CPP %s -// RUN: FileCheck -input-file=%T/used-helper-decls/helper_decls_test.cpp -check-prefix=CHECK-OLD-CLASS1-CPP %s +// RUN: clang-move -names="a::Class1" -new_cc=%t.dir/used-helper-decls/new_helper_decls_test.cpp -new_header=%t.dir/used-helper-decls/new_helper_decls_test.h -old_cc=%t.dir/used-helper-decls/helper_decls_test.cpp -old_header=../used-helper-decls/helper_decls_test.h %t.dir/used-helper-decls/helper_decls_test.cpp -- -std=c++11 +// RUN: FileCheck -input-file=%t.dir/used-helper-decls/new_helper_decls_test.cpp -check-prefix=CHECK-NEW-CLASS1-CPP %s +// RUN: FileCheck -input-file=%t.dir/used-helper-decls/helper_decls_test.cpp -check-prefix=CHECK-OLD-CLASS1-CPP %s // CHECK-NEW-CLASS1-CPP: #include "{{.*}}new_helper_decls_test.h" // CHECK-NEW-CLASS1-CPP-SAME: {{[[:space:]]}} @@ -31,10 +31,10 @@ // ---------------------------------------------------------------------------- // Test moving used helper function and its transitively used static variables. // ---------------------------------------------------------------------------- -// RUN: cp %S/Inputs/helper_decls_test* %T/used-helper-decls/ -// RUN: clang-move -names="a::Class2" -new_cc=%T/used-helper-decls/new_helper_decls_test.cpp -new_header=%T/used-helper-decls/new_helper_decls_test.h -old_cc=%T/used-helper-decls/helper_decls_test.cpp -old_header=../used-helper-decls/helper_decls_test.h %T/used-helper-decls/helper_decls_test.cpp -- -std=c++11 -// RUN: FileCheck -input-file=%T/used-helper-decls/new_helper_decls_test.cpp -check-prefix=CHECK-NEW-CLASS2-CPP %s -// RUN: FileCheck -input-file=%T/used-helper-decls/helper_decls_test.cpp -check-prefix=CHECK-OLD-CLASS2-CPP %s +// RUN: cp %S/Inputs/helper_decls_test* %t.dir/used-helper-decls/ +// RUN: clang-move -names="a::Class2" -new_cc=%t.dir/used-helper-decls/new_helper_decls_test.cpp -new_header=%t.dir/used-helper-decls/new_helper_decls_test.h -old_cc=%t.dir/used-helper-decls/helper_decls_test.cpp -old_header=../used-helper-decls/helper_decls_test.h %t.dir/used-helper-decls/helper_decls_test.cpp -- -std=c++11 +// RUN: FileCheck -input-file=%t.dir/used-helper-decls/new_helper_decls_test.cpp -check-prefix=CHECK-NEW-CLASS2-CPP %s +// RUN: FileCheck -input-file=%t.dir/used-helper-decls/helper_decls_test.cpp -check-prefix=CHECK-OLD-CLASS2-CPP %s // CHECK-NEW-CLASS2-CPP: #include "{{.*}}new_helper_decls_test.h" // CHECK-NEW-CLASS2-CPP-SAME: {{[[:space:]]}} @@ -67,10 +67,10 @@ // ---------------------------------------------------------------------------- // Test using a static member variable of a helper class. // ---------------------------------------------------------------------------- -// RUN: cp %S/Inputs/helper_decls_test* %T/used-helper-decls/ -// RUN: clang-move -names="a::Class3" -new_cc=%T/used-helper-decls/new_helper_decls_test.cpp -new_header=%T/used-helper-decls/new_helper_decls_test.h -old_cc=%T/used-helper-decls/helper_decls_test.cpp -old_header=../used-helper-decls/helper_decls_test.h %T/used-helper-decls/helper_decls_test.cpp -- -std=c++11 -// RUN: FileCheck -input-file=%T/used-helper-decls/new_helper_decls_test.cpp -check-prefix=CHECK-NEW-CLASS3-CPP %s -// RUN: FileCheck -input-file=%T/used-helper-decls/helper_decls_test.cpp -check-prefix=CHECK-OLD-CLASS3-CPP %s +// RUN: cp %S/Inputs/helper_decls_test* %t.dir/used-helper-decls/ +// RUN: clang-move -names="a::Class3" -new_cc=%t.dir/used-helper-decls/new_helper_decls_test.cpp -new_header=%t.dir/used-helper-decls/new_helper_decls_test.h -old_cc=%t.dir/used-helper-decls/helper_decls_test.cpp -old_header=../used-helper-decls/helper_decls_test.h %t.dir/used-helper-decls/helper_decls_test.cpp -- -std=c++11 +// RUN: FileCheck -input-file=%t.dir/used-helper-decls/new_helper_decls_test.cpp -check-prefix=CHECK-NEW-CLASS3-CPP %s +// RUN: FileCheck -input-file=%t.dir/used-helper-decls/helper_decls_test.cpp -check-prefix=CHECK-OLD-CLASS3-CPP %s // CHECK-NEW-CLASS3-CPP: #include "{{.*}}new_helper_decls_test.h" // CHECK-NEW-CLASS3-CPP-SAME: {{[[:space:]]}} @@ -99,10 +99,10 @@ // ---------------------------------------------------------------------------- // Test moving helper classes. // ---------------------------------------------------------------------------- -// RUN: cp %S/Inputs/helper_decls_test* %T/used-helper-decls/ -// RUN: clang-move -names="a::Class4" -new_cc=%T/used-helper-decls/new_helper_decls_test.cpp -new_header=%T/used-helper-decls/new_helper_decls_test.h -old_cc=%T/used-helper-decls/helper_decls_test.cpp -old_header=../used-helper-decls/helper_decls_test.h %T/used-helper-decls/helper_decls_test.cpp -- -std=c++11 -// RUN: FileCheck -input-file=%T/used-helper-decls/new_helper_decls_test.cpp -check-prefix=CHECK-NEW-CLASS4-CPP %s -// RUN: FileCheck -input-file=%T/used-helper-decls/helper_decls_test.cpp -check-prefix=CHECK-OLD-CLASS4-CPP %s +// RUN: cp %S/Inputs/helper_decls_test* %t.dir/used-helper-decls/ +// RUN: clang-move -names="a::Class4" -new_cc=%t.dir/used-helper-decls/new_helper_decls_test.cpp -new_header=%t.dir/used-helper-decls/new_helper_decls_test.h -old_cc=%t.dir/used-helper-decls/helper_decls_test.cpp -old_header=../used-helper-decls/helper_decls_test.h %t.dir/used-helper-decls/helper_decls_test.cpp -- -std=c++11 +// RUN: FileCheck -input-file=%t.dir/used-helper-decls/new_helper_decls_test.cpp -check-prefix=CHECK-NEW-CLASS4-CPP %s +// RUN: FileCheck -input-file=%t.dir/used-helper-decls/helper_decls_test.cpp -check-prefix=CHECK-OLD-CLASS4-CPP %s // CHECK-NEW-CLASS4-CPP: #include "{{.*}}new_helper_decls_test.h" // CHECK-NEW-CLASS4-CPP-SAME: {{[[:space:]]}} @@ -120,10 +120,10 @@ // ---------------------------------------------------------------------------- // Test moving helper variables and helper functions together. // ---------------------------------------------------------------------------- -// RUN: cp %S/Inputs/helper_decls_test* %T/used-helper-decls/ -// RUN: clang-move -names="a::Class5" -new_cc=%T/used-helper-decls/new_helper_decls_test.cpp -new_header=%T/used-helper-decls/new_helper_decls_test.h -old_cc=%T/used-helper-decls/helper_decls_test.cpp -old_header=../used-helper-decls/helper_decls_test.h %T/used-helper-decls/helper_decls_test.cpp -- -std=c++11 -// RUN: FileCheck -input-file=%T/used-helper-decls/new_helper_decls_test.cpp -check-prefix=CHECK-NEW-CLASS5-CPP %s -// RUN: FileCheck -input-file=%T/used-helper-decls/helper_decls_test.cpp -check-prefix=CHECK-OLD-CLASS5-CPP %s +// RUN: cp %S/Inputs/helper_decls_test* %t.dir/used-helper-decls/ +// RUN: clang-move -names="a::Class5" -new_cc=%t.dir/used-helper-decls/new_helper_decls_test.cpp -new_header=%t.dir/used-helper-decls/new_helper_decls_test.h -old_cc=%t.dir/used-helper-decls/helper_decls_test.cpp -old_header=../used-helper-decls/helper_decls_test.h %t.dir/used-helper-decls/helper_decls_test.cpp -- -std=c++11 +// RUN: FileCheck -input-file=%t.dir/used-helper-decls/new_helper_decls_test.cpp -check-prefix=CHECK-NEW-CLASS5-CPP %s +// RUN: FileCheck -input-file=%t.dir/used-helper-decls/helper_decls_test.cpp -check-prefix=CHECK-OLD-CLASS5-CPP %s // CHECK-NEW-CLASS5-CPP: #include "{{.*}}new_helper_decls_test.h" // CHECK-NEW-CLASS5-CPP-SAME: {{[[:space:]]}} @@ -153,10 +153,10 @@ // ---------------------------------------------------------------------------- // Test moving helper variables and their transitively used helper classes. // ---------------------------------------------------------------------------- -// RUN: cp %S/Inputs/helper_decls_test* %T/used-helper-decls/ -// RUN: clang-move -names="a::Class6" -new_cc=%T/used-helper-decls/new_helper_decls_test.cpp -new_header=%T/used-helper-decls/new_helper_decls_test.h -old_cc=%T/used-helper-decls/helper_decls_test.cpp -old_header=../used-helper-decls/helper_decls_test.h %T/used-helper-decls/helper_decls_test.cpp -- -std=c++11 -// RUN: FileCheck -input-file=%T/used-helper-decls/new_helper_decls_test.cpp -check-prefix=CHECK-NEW-CLASS6-CPP %s -// RUN: FileCheck -input-file=%T/used-helper-decls/helper_decls_test.cpp -check-prefix=CHECK-OLD-CLASS6-CPP %s +// RUN: cp %S/Inputs/helper_decls_test* %t.dir/used-helper-decls/ +// RUN: clang-move -names="a::Class6" -new_cc=%t.dir/used-helper-decls/new_helper_decls_test.cpp -new_header=%t.dir/used-helper-decls/new_helper_decls_test.h -old_cc=%t.dir/used-helper-decls/helper_decls_test.cpp -old_header=../used-helper-decls/helper_decls_test.h %t.dir/used-helper-decls/helper_decls_test.cpp -- -std=c++11 +// RUN: FileCheck -input-file=%t.dir/used-helper-decls/new_helper_decls_test.cpp -check-prefix=CHECK-NEW-CLASS6-CPP %s +// RUN: FileCheck -input-file=%t.dir/used-helper-decls/helper_decls_test.cpp -check-prefix=CHECK-OLD-CLASS6-CPP %s // CHECK-NEW-CLASS6-CPP: #include "{{.*}}new_helper_decls_test.h" // CHECK-NEW-CLASS6-CPP-SAME: {{[[:space:]]}} @@ -186,10 +186,10 @@ // ---------------------------------------------------------------------------- // Test moving classes where its methods use helpers. // ---------------------------------------------------------------------------- -// RUN: cp %S/Inputs/helper_decls_test* %T/used-helper-decls/ -// RUN: clang-move -names="a::Class7" -new_cc=%T/used-helper-decls/new_helper_decls_test.cpp -new_header=%T/used-helper-decls/new_helper_decls_test.h -old_cc=%T/used-helper-decls/helper_decls_test.cpp -old_header=../used-helper-decls/helper_decls_test.h %T/used-helper-decls/helper_decls_test.cpp -- -std=c++11 -// RUN: FileCheck -input-file=%T/used-helper-decls/new_helper_decls_test.cpp -check-prefix=CHECK-NEW-CLASS7-CPP %s -// RUN: FileCheck -input-file=%T/used-helper-decls/helper_decls_test.cpp -check-prefix=CHECK-OLD-CLASS7-CPP %s +// RUN: cp %S/Inputs/helper_decls_test* %t.dir/used-helper-decls/ +// RUN: clang-move -names="a::Class7" -new_cc=%t.dir/used-helper-decls/new_helper_decls_test.cpp -new_header=%t.dir/used-helper-decls/new_helper_decls_test.h -old_cc=%t.dir/used-helper-decls/helper_decls_test.cpp -old_header=../used-helper-decls/helper_decls_test.h %t.dir/used-helper-decls/helper_decls_test.cpp -- -std=c++11 +// RUN: FileCheck -input-file=%t.dir/used-helper-decls/new_helper_decls_test.cpp -check-prefix=CHECK-NEW-CLASS7-CPP %s +// RUN: FileCheck -input-file=%t.dir/used-helper-decls/helper_decls_test.cpp -check-prefix=CHECK-OLD-CLASS7-CPP %s // CHECK-NEW-CLASS7-CPP: #include "{{.*}}new_helper_decls_test.h" // CHECK-NEW-CLASS7-CPP-SAME: {{[[:space:]]}} @@ -218,10 +218,10 @@ // ---------------------------------------------------------------------------- // Test moving helper function and its transitively used helper variables. // ---------------------------------------------------------------------------- -// RUN: cp %S/Inputs/helper_decls_test* %T/used-helper-decls/ -// RUN: clang-move -names="a::Fun1" -new_cc=%T/used-helper-decls/new_helper_decls_test.cpp -new_header=%T/used-helper-decls/new_helper_decls_test.h -old_cc=%T/used-helper-decls/helper_decls_test.cpp -old_header=../used-helper-decls/helper_decls_test.h %T/used-helper-decls/helper_decls_test.cpp -- -std=c++11 -// RUN: FileCheck -input-file=%T/used-helper-decls/new_helper_decls_test.cpp -check-prefix=CHECK-NEW-FUN1-CPP %s -// RUN: FileCheck -input-file=%T/used-helper-decls/helper_decls_test.cpp -check-prefix=CHECK-OLD-FUN1-CPP %s +// RUN: cp %S/Inputs/helper_decls_test* %t.dir/used-helper-decls/ +// RUN: clang-move -names="a::Fun1" -new_cc=%t.dir/used-helper-decls/new_helper_decls_test.cpp -new_header=%t.dir/used-helper-decls/new_helper_decls_test.h -old_cc=%t.dir/used-helper-decls/helper_decls_test.cpp -old_header=../used-helper-decls/helper_decls_test.h %t.dir/used-helper-decls/helper_decls_test.cpp -- -std=c++11 +// RUN: FileCheck -input-file=%t.dir/used-helper-decls/new_helper_decls_test.cpp -check-prefix=CHECK-NEW-FUN1-CPP %s +// RUN: FileCheck -input-file=%t.dir/used-helper-decls/helper_decls_test.cpp -check-prefix=CHECK-OLD-FUN1-CPP %s // CHECK-NEW-FUN1-CPP: #include "{{.*}}new_helper_decls_test.h" // CHECK-NEW-FUN1-CPP-SAME: {{[[:space:]]}} @@ -244,11 +244,11 @@ // ---------------------------------------------------------------------------- // Test no moving helpers when moving inline functions in header. // ---------------------------------------------------------------------------- -// RUN: cp %S/Inputs/helper_decls_test* %T/used-helper-decls/ -// RUN: clang-move -names="a::Fun2" -new_cc=%T/used-helper-decls/new_helper_decls_test.cpp -new_header=%T/used-helper-decls/new_helper_decls_test.h -old_cc=%T/used-helper-decls/helper_decls_test.cpp -old_header=../used-helper-decls/helper_decls_test.h %T/used-helper-decls/helper_decls_test.cpp -- -std=c++11 -// RUN: FileCheck -input-file=%T/used-helper-decls/new_helper_decls_test.cpp -check-prefix=CHECK-NEW-FUN2-CPP %s -// RUN: FileCheck -input-file=%T/used-helper-decls/new_helper_decls_test.h -check-prefix=CHECK-NEW-FUN2-H %s -// RUN: FileCheck -input-file=%T/used-helper-decls/helper_decls_test.h -check-prefix=CHECK-OLD-FUN2-H %s +// RUN: cp %S/Inputs/helper_decls_test* %t.dir/used-helper-decls/ +// RUN: clang-move -names="a::Fun2" -new_cc=%t.dir/used-helper-decls/new_helper_decls_test.cpp -new_header=%t.dir/used-helper-decls/new_helper_decls_test.h -old_cc=%t.dir/used-helper-decls/helper_decls_test.cpp -old_header=../used-helper-decls/helper_decls_test.h %t.dir/used-helper-decls/helper_decls_test.cpp -- -std=c++11 +// RUN: FileCheck -input-file=%t.dir/used-helper-decls/new_helper_decls_test.cpp -check-prefix=CHECK-NEW-FUN2-CPP %s +// RUN: FileCheck -input-file=%t.dir/used-helper-decls/new_helper_decls_test.h -check-prefix=CHECK-NEW-FUN2-H %s +// RUN: FileCheck -input-file=%t.dir/used-helper-decls/helper_decls_test.h -check-prefix=CHECK-OLD-FUN2-H %s // CHECK-NEW-FUN2-H: namespace a { // CHECK-NEW-FUN2-H-NEXT: inline void Fun2() {} @@ -262,10 +262,10 @@ // ---------------------------------------------------------------------------- // Test moving used helper function and its transitively used functions. // ---------------------------------------------------------------------------- -// RUN: cp %S/Inputs/helper_decls_test* %T/used-helper-decls/ -// RUN: clang-move -names="b::Fun3" -new_cc=%T/used-helper-decls/new_helper_decls_test.cpp -new_header=%T/used-helper-decls/new_helper_decls_test.h -old_cc=%T/used-helper-decls/helper_decls_test.cpp -old_header=../used-helper-decls/helper_decls_test.h %T/used-helper-decls/helper_decls_test.cpp -- -std=c++11 -// RUN: FileCheck -input-file=%T/used-helper-decls/new_helper_decls_test.cpp -check-prefix=CHECK-NEW-FUN3-CPP %s -// RUN: FileCheck -input-file=%T/used-helper-decls/helper_decls_test.cpp -check-prefix=CHECK-OLD-FUN3-CPP %s +// RUN: cp %S/Inputs/helper_decls_test* %t.dir/used-helper-decls/ +// RUN: clang-move -names="b::Fun3" -new_cc=%t.dir/used-helper-decls/new_helper_decls_test.cpp -new_header=%t.dir/used-helper-decls/new_helper_decls_test.h -old_cc=%t.dir/used-helper-decls/helper_decls_test.cpp -old_header=../used-helper-decls/helper_decls_test.h %t.dir/used-helper-decls/helper_decls_test.cpp -- -std=c++11 +// RUN: FileCheck -input-file=%t.dir/used-helper-decls/new_helper_decls_test.cpp -check-prefix=CHECK-NEW-FUN3-CPP %s +// RUN: FileCheck -input-file=%t.dir/used-helper-decls/helper_decls_test.cpp -check-prefix=CHECK-OLD-FUN3-CPP %s // CHECK-NEW-FUN3-CPP: #include "{{.*}}new_helper_decls_test.h" // CHECK-NEW-FUN3-CPP-SAME: {{[[:space:]]}} @@ -294,12 +294,12 @@ // ---------------------------------------------------------------------------- // Test moving all symbols in headers. // ---------------------------------------------------------------------------- -// RUN: cp %S/Inputs/helper_decls_test* %T/used-helper-decls/ -// RUN: clang-move -names="a::Class1, a::Class2, a::Class3, a::Class4, a::Class5, a::Class5, a::Class6, a::Class7, a::Fun1, a::Fun2, b::Fun3" -new_cc=%T/used-helper-decls/new_helper_decls_test.cpp -new_header=%T/used-helper-decls/new_helper_decls_test.h -old_cc=%T/used-helper-decls/helper_decls_test.cpp -old_header=../used-helper-decls/helper_decls_test.h %T/used-helper-decls/helper_decls_test.cpp -- -std=c++11 -// RUN: FileCheck -input-file=%T/used-helper-decls/new_helper_decls_test.h -check-prefix=CHECK-NEW-H %s -// RUN: FileCheck -input-file=%T/used-helper-decls/new_helper_decls_test.cpp -check-prefix=CHECK-NEW-CPP %s -// RUN: FileCheck -input-file=%T/used-helper-decls/helper_decls_test.h -allow-empty -check-prefix=CHECK-EMPTY %s -// RUN: FileCheck -input-file=%T/used-helper-decls/helper_decls_test.cpp -allow-empty -check-prefix=CHECK-EMPTY %s +// RUN: cp %S/Inputs/helper_decls_test* %t.dir/used-helper-decls/ +// RUN: clang-move -names="a::Class1, a::Class2, a::Class3, a::Class4, a::Class5, a::Class5, a::Class6, a::Class7, a::Fun1, a::Fun2, b::Fun3" -new_cc=%t.dir/used-helper-decls/new_helper_decls_test.cpp -new_header=%t.dir/used-helper-decls/new_helper_decls_test.h -old_cc=%t.dir/used-helper-decls/helper_decls_test.cpp -old_header=../used-helper-decls/helper_decls_test.h %t.dir/used-helper-decls/helper_decls_test.cpp -- -std=c++11 +// RUN: FileCheck -input-file=%t.dir/used-helper-decls/new_helper_decls_test.h -check-prefix=CHECK-NEW-H %s +// RUN: FileCheck -input-file=%t.dir/used-helper-decls/new_helper_decls_test.cpp -check-prefix=CHECK-NEW-CPP %s +// RUN: FileCheck -input-file=%t.dir/used-helper-decls/helper_decls_test.h -allow-empty -check-prefix=CHECK-EMPTY %s +// RUN: FileCheck -input-file=%t.dir/used-helper-decls/helper_decls_test.cpp -allow-empty -check-prefix=CHECK-EMPTY %s // CHECK-NEW-H: namespace a { diff --git a/clang-tools-extra/test/clang-move/move-var.cpp b/clang-tools-extra/test/clang-move/move-var.cpp index 4a3554c..bacba0b 100644 --- a/clang-tools-extra/test/clang-move/move-var.cpp +++ b/clang-tools-extra/test/clang-move/move-var.cpp @@ -1,11 +1,11 @@ -// RUN: mkdir -p %T/move-var -// RUN: cp %S/Inputs/var_test* %T/move-var -// RUN: cd %T/move-var -// RUN: clang-move -names="a::kGlobalInt" -new_header=%T/move-var/new_var_test.h -old_header=../move-var/var_test.h -old_cc=../move-var/var_test.cpp -new_cc=%T/move-var/new_var_test.cpp %T/move-var/var_test.cpp -- -// RUN: FileCheck -input-file=%T/move-var/var_test.h -check-prefix=CHECK-OLD-VAR-H-CASE1 %s -// RUN: FileCheck -input-file=%T/move-var/var_test.cpp -check-prefix=CHECK-OLD-VAR-CPP-CASE1 %s -// RUN: FileCheck -input-file=%T/move-var/new_var_test.h -check-prefix=CHECK-NEW-VAR-H-CASE1 %s -// RUN: FileCheck -input-file=%T/move-var/new_var_test.cpp -check-prefix=CHECK-NEW-VAR-CPP-CASE1 %s +// RUN: mkdir -p %t.dir/move-var +// RUN: cp %S/Inputs/var_test* %t.dir/move-var +// RUN: cd %t.dir/move-var +// RUN: clang-move -names="a::kGlobalInt" -new_header=%t.dir/move-var/new_var_test.h -old_header=../move-var/var_test.h -old_cc=../move-var/var_test.cpp -new_cc=%t.dir/move-var/new_var_test.cpp %t.dir/move-var/var_test.cpp -- +// RUN: FileCheck -input-file=%t.dir/move-var/var_test.h -check-prefix=CHECK-OLD-VAR-H-CASE1 %s +// RUN: FileCheck -input-file=%t.dir/move-var/var_test.cpp -check-prefix=CHECK-OLD-VAR-CPP-CASE1 %s +// RUN: FileCheck -input-file=%t.dir/move-var/new_var_test.h -check-prefix=CHECK-NEW-VAR-H-CASE1 %s +// RUN: FileCheck -input-file=%t.dir/move-var/new_var_test.cpp -check-prefix=CHECK-NEW-VAR-CPP-CASE1 %s // CHECK-OLD-VAR-H-CASE1-NOT: extern int kGlobalInt; // CHECK-OLD-VAR-H-CASE1: int kGlobalInt = 3; @@ -18,12 +18,12 @@ // CHECK-NEW-VAR-CPP-CASE1: int kGlobalInt = 1; -// RUN: cp %S/Inputs/var_test* %T/move-var -// RUN: clang-move -names="a::kGlobalStr" -new_header=%T/move-var/new_var_test.h -old_header=../move-var/var_test.h -old_cc=../move-var/var_test.cpp -new_cc=%T/move-var/new_var_test.cpp %T/move-var/var_test.cpp -- -// RUN: FileCheck -input-file=%T/move-var/var_test.h -check-prefix=CHECK-OLD-VAR-H-CASE2 %s -// RUN: FileCheck -input-file=%T/move-var/var_test.cpp -check-prefix=CHECK-OLD-VAR-CPP-CASE2 %s -// RUN: FileCheck -input-file=%T/move-var/new_var_test.h -check-prefix=CHECK-NEW-VAR-H-CASE2 %s -// RUN: FileCheck -input-file=%T/move-var/new_var_test.cpp -check-prefix=CHECK-NEW-VAR-CPP-CASE2 %s +// RUN: cp %S/Inputs/var_test* %t.dir/move-var +// RUN: clang-move -names="a::kGlobalStr" -new_header=%t.dir/move-var/new_var_test.h -old_header=../move-var/var_test.h -old_cc=../move-var/var_test.cpp -new_cc=%t.dir/move-var/new_var_test.cpp %t.dir/move-var/var_test.cpp -- +// RUN: FileCheck -input-file=%t.dir/move-var/var_test.h -check-prefix=CHECK-OLD-VAR-H-CASE2 %s +// RUN: FileCheck -input-file=%t.dir/move-var/var_test.cpp -check-prefix=CHECK-OLD-VAR-CPP-CASE2 %s +// RUN: FileCheck -input-file=%t.dir/move-var/new_var_test.h -check-prefix=CHECK-NEW-VAR-H-CASE2 %s +// RUN: FileCheck -input-file=%t.dir/move-var/new_var_test.cpp -check-prefix=CHECK-NEW-VAR-CPP-CASE2 %s // CHECK-OLD-VAR-H-CASE2-NOT: extern const char *const kGlobalStr; // CHECK-OLD-VAR-H-CASE2: const char *const kGlobalStr = "Hello2"; @@ -36,10 +36,10 @@ // CHECK-NEW-VAR-CPP-CASE2: const char *const kGlobalStr = "Hello"; -// RUN: cp %S/Inputs/var_test* %T/move-var -// RUN: clang-move -names="kEvilInt" -new_header=%T/move-var/new_var_test.h -old_header=../move-var/var_test.h -old_cc=../move-var/var_test.cpp -new_cc=%T/move-var/new_var_test.cpp %T/move-var/var_test.cpp -- -// RUN: FileCheck -input-file=%T/move-var/var_test.h -check-prefix=CHECK-OLD-VAR-H-CASE3 %s -// RUN: FileCheck -input-file=%T/move-var/new_var_test.h -check-prefix=CHECK-NEW-VAR-H-CASE3 %s +// RUN: cp %S/Inputs/var_test* %t.dir/move-var +// RUN: clang-move -names="kEvilInt" -new_header=%t.dir/move-var/new_var_test.h -old_header=../move-var/var_test.h -old_cc=../move-var/var_test.cpp -new_cc=%t.dir/move-var/new_var_test.cpp %t.dir/move-var/var_test.cpp -- +// RUN: FileCheck -input-file=%t.dir/move-var/var_test.h -check-prefix=CHECK-OLD-VAR-H-CASE3 %s +// RUN: FileCheck -input-file=%t.dir/move-var/new_var_test.h -check-prefix=CHECK-NEW-VAR-H-CASE3 %s // CHECK-OLD-VAR-H-CASE3-NOT: int kEvilInt = 2; diff --git a/clang-tools-extra/test/clang-move/no-move-macro-helpers.cpp b/clang-tools-extra/test/clang-move/no-move-macro-helpers.cpp index 282eee0..e7a5b4e 100644 --- a/clang-tools-extra/test/clang-move/no-move-macro-helpers.cpp +++ b/clang-tools-extra/test/clang-move/no-move-macro-helpers.cpp @@ -1,16 +1,16 @@ -// RUN: mkdir -p %T/no-move-macro-helper -// RUN: cat %S/Inputs/macro_helper_test.h > %T/no-move-macro-helper/macro_helper_test.h -// RUN: cat %S/Inputs/macro_helper_test.cpp > %T/no-move-macro-helper/macro_helper_test.cpp -// RUN: cd %T/no-move-macro-helper +// RUN: mkdir -p %t.dir/no-move-macro-helper +// RUN: cat %S/Inputs/macro_helper_test.h > %t.dir/no-move-macro-helper/macro_helper_test.h +// RUN: cat %S/Inputs/macro_helper_test.cpp > %t.dir/no-move-macro-helper/macro_helper_test.cpp +// RUN: cd %t.dir/no-move-macro-helper // // ----------------------------------------------------------------------------- // Test no moving helpers in macro. // ----------------------------------------------------------------------------- -// RUN: clang-move -names="A" -new_cc=%T/no-move-macro-helper/new_test.cpp -new_header=%T/no-move-macro-helper/new_test.h -old_cc=%T/no-move-macro-helper/macro_helper_test.cpp -old_header=%T/no-move-macro-helper/macro_helper_test.h %T/no-move-macro-helper/macro_helper_test.cpp -- -std=c++11 -// RUN: FileCheck -input-file=%T/no-move-macro-helper/new_test.h -check-prefix=CHECK-NEW-TEST-CASE1-H %s -// RUN: FileCheck -input-file=%T/no-move-macro-helper/new_test.cpp -check-prefix=CHECK-NEW-TEST-CASE1-CPP %s -// RUN: FileCheck -input-file=%T/no-move-macro-helper/macro_helper_test.h -check-prefix=CHECK-OLD-TEST-CASE1-H %s -// RUN: FileCheck -input-file=%T/no-move-macro-helper/macro_helper_test.cpp -check-prefix=CHECK-OLD-TEST-CASE1-CPP %s +// RUN: clang-move -names="A" -new_cc=%t.dir/no-move-macro-helper/new_test.cpp -new_header=%t.dir/no-move-macro-helper/new_test.h -old_cc=%t.dir/no-move-macro-helper/macro_helper_test.cpp -old_header=%t.dir/no-move-macro-helper/macro_helper_test.h %t.dir/no-move-macro-helper/macro_helper_test.cpp -- -std=c++11 +// RUN: FileCheck -input-file=%t.dir/no-move-macro-helper/new_test.h -check-prefix=CHECK-NEW-TEST-CASE1-H %s +// RUN: FileCheck -input-file=%t.dir/no-move-macro-helper/new_test.cpp -check-prefix=CHECK-NEW-TEST-CASE1-CPP %s +// RUN: FileCheck -input-file=%t.dir/no-move-macro-helper/macro_helper_test.h -check-prefix=CHECK-OLD-TEST-CASE1-H %s +// RUN: FileCheck -input-file=%t.dir/no-move-macro-helper/macro_helper_test.cpp -check-prefix=CHECK-OLD-TEST-CASE1-CPP %s // CHECK-NEW-TEST-CASE1-H: class A {}; @@ -24,14 +24,14 @@ // ----------------------------------------------------------------------------- // Test moving all. // ----------------------------------------------------------------------------- -// RUN: cat %S/Inputs/macro_helper_test.h > %T/no-move-macro-helper/macro_helper_test.h -// RUN: cat %S/Inputs/macro_helper_test.cpp > %T/no-move-macro-helper/macro_helper_test.cpp -// RUN: clang-move -names="A, f1" -new_cc=%T/no-move-macro-helper/new_test.cpp -new_header=%T/no-move-macro-helper/new_test.h -old_cc=%T/no-move-macro-helper/macro_helper_test.cpp -old_header=%T/no-move-macro-helper/macro_helper_test.h %T/no-move-macro-helper/macro_helper_test.cpp -- -std=c++11 +// RUN: cat %S/Inputs/macro_helper_test.h > %t.dir/no-move-macro-helper/macro_helper_test.h +// RUN: cat %S/Inputs/macro_helper_test.cpp > %t.dir/no-move-macro-helper/macro_helper_test.cpp +// RUN: clang-move -names="A, f1" -new_cc=%t.dir/no-move-macro-helper/new_test.cpp -new_header=%t.dir/no-move-macro-helper/new_test.h -old_cc=%t.dir/no-move-macro-helper/macro_helper_test.cpp -old_header=%t.dir/no-move-macro-helper/macro_helper_test.h %t.dir/no-move-macro-helper/macro_helper_test.cpp -- -std=c++11 // -// RUN: FileCheck -input-file=%T/no-move-macro-helper/new_test.h -check-prefix=CHECK-NEW-TEST-CASE2-H %s -// RUN: FileCheck -input-file=%T/no-move-macro-helper/new_test.cpp -check-prefix=CHECK-NEW-TEST-CASE2-CPP %s -// RUN: FileCheck -input-file=%T/no-move-macro-helper/macro_helper_test.h -allow-empty -check-prefix=CHECK-EMPTY %s -// RUN: FileCheck -input-file=%T/no-move-macro-helper/macro_helper_test.cpp -allow-empty -check-prefix=CHECK-EMPTY %s +// RUN: FileCheck -input-file=%t.dir/no-move-macro-helper/new_test.h -check-prefix=CHECK-NEW-TEST-CASE2-H %s +// RUN: FileCheck -input-file=%t.dir/no-move-macro-helper/new_test.cpp -check-prefix=CHECK-NEW-TEST-CASE2-CPP %s +// RUN: FileCheck -input-file=%t.dir/no-move-macro-helper/macro_helper_test.h -allow-empty -check-prefix=CHECK-EMPTY %s +// RUN: FileCheck -input-file=%t.dir/no-move-macro-helper/macro_helper_test.cpp -allow-empty -check-prefix=CHECK-EMPTY %s // CHECK-NEW-TEST-CASE2-H: class A {}; // CHECK-NEW-TEST-CASE2-H-NEXT:void f1(); diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/invalid-enum-default-initialization.c b/clang-tools-extra/test/clang-tidy/checkers/bugprone/invalid-enum-default-initialization.c new file mode 100644 index 0000000..55f5884 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/invalid-enum-default-initialization.c @@ -0,0 +1,54 @@ +// RUN: %check_clang_tidy %s bugprone-invalid-enum-default-initialization %t + +enum Enum1 { + Enum1_A = 1, + Enum1_B +}; + +struct Struct1 { + int a; + enum Enum1 b; +}; + +struct Struct2 { + struct Struct1 a; + char b; +}; + +enum Enum1 E1 = {}; +// CHECK-NOTES: :[[@LINE-1]]:17: warning: enum value of type 'Enum1' initialized with invalid value of 0, enum doesn't have a zero-value enumerator +// CHECK-NOTES: :3:6: note: enum is defined here +enum Enum1 E2[10] = {}; +// CHECK-NOTES: :[[@LINE-1]]:21: warning: enum value of type 'Enum1' initialized with invalid value of 0, enum doesn't have a zero-value enumerator +// CHECK-NOTES: :3:6: note: enum is defined here +enum Enum1 E3[10] = {Enum1_A}; +// CHECK-NOTES: :[[@LINE-1]]:21: warning: enum value of type 'Enum1' initialized with invalid value of 0, enum doesn't have a zero-value enumerator +// CHECK-NOTES: :3:6: note: enum is defined here +enum Enum1 E4[2][2] = {{Enum1_A}, {Enum1_A}}; +// CHECK-NOTES: :[[@LINE-1]]:24: warning: enum value of type 'Enum1' initialized with invalid value of 0, enum doesn't have a zero-value enumerator +// CHECK-NOTES: :3:6: note: enum is defined here +// CHECK-NOTES: :[[@LINE-3]]:35: warning: enum value of type 'Enum1' initialized with invalid value of 0, enum doesn't have a zero-value enumerator +// CHECK-NOTES: :3:6: note: enum is defined here +enum Enum1 E5[2][2] = {{Enum1_A, Enum1_A}}; +// CHECK-NOTES: :[[@LINE-1]]:23: warning: enum value of type 'Enum1' initialized with invalid value of 0, enum doesn't have a zero-value enumerator +// CHECK-NOTES: :3:6: note: enum is defined here + + +struct Struct1 S1[2][2] = {{{1, Enum1_A}, {2, Enum1_A}}}; +// CHECK-NOTES: :[[@LINE-1]]:27: warning: enum value of type 'Enum1' initialized with invalid value of 0, enum doesn't have a zero-value enumerator +// CHECK-NOTES: :3:6: note: enum is defined here + +struct Struct2 S2[3] = {{1}}; +// CHECK-NOTES: :[[@LINE-1]]:24: warning: enum value of type 'Enum1' initialized with invalid value of 0, enum doesn't have a zero-value enumerator +// CHECK-NOTES: :3:6: note: enum is defined here +// CHECK-NOTES: :[[@LINE-3]]:26: warning: enum value of type 'Enum1' initialized with invalid value of 0, enum doesn't have a zero-value enumerator +// CHECK-NOTES: :3:6: note: enum is defined here + +union Union1 { + enum Enum1 a; + int b; +}; + +// no warnings for union +union Union1 U1 = {}; +union Union1 U2[3] = {}; diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/invalid-enum-default-initialization.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/invalid-enum-default-initialization.cpp new file mode 100644 index 0000000..eb3d563 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/invalid-enum-default-initialization.cpp @@ -0,0 +1,145 @@ +// RUN: %check_clang_tidy -std=c++17 %s bugprone-invalid-enum-default-initialization %t + +enum class Enum0: int { + A = 0, + B +}; + +enum class Enum1: int { + A = 1, + B +}; + +enum Enum2 { + Enum_A = 4, + Enum_B +}; + +Enum0 E0_1{}; +Enum0 E0_2 = Enum0(); +Enum0 E0_3; +Enum0 E0_4{0}; +Enum0 E0_5{Enum0::A}; +Enum0 E0_6{Enum0::B}; + +Enum1 E1_1{}; +// CHECK-NOTES: :[[@LINE-1]]:11: warning: enum value of type 'Enum1' initialized with invalid value of 0, enum doesn't have a zero-value enumerator +// CHECK-NOTES: :8:12: note: enum is defined here +Enum1 E1_2 = Enum1(); +// CHECK-NOTES: :[[@LINE-1]]:14: warning: enum value of type 'Enum1' initialized with invalid value of 0, enum doesn't have a zero-value enumerator +// CHECK-NOTES: :8:12: note: enum is defined here +Enum1 E1_3; +Enum1 E1_4{0}; +Enum1 E1_5{Enum1::A}; +Enum1 E1_6{Enum1::B}; + +Enum2 E2_1{}; +// CHECK-NOTES: :[[@LINE-1]]:11: warning: enum value of type 'Enum2' initialized with invalid value of 0, enum doesn't have a zero-value enumerator +// CHECK-NOTES: :13:6: note: enum is defined here +Enum2 E2_2 = Enum2(); +// CHECK-NOTES: :[[@LINE-1]]:14: warning: enum value of type 'Enum2' initialized with invalid value of 0, enum doesn't have a zero-value enumerator +// CHECK-NOTES: :13:6: note: enum is defined here + +void f1() { + static Enum1 S; // FIMXE: warn for this? + Enum1 A; + Enum1 B = Enum1(); + // CHECK-NOTES: :[[@LINE-1]]:13: warning: enum value of type 'Enum1' initialized with invalid value of 0, enum doesn't have a zero-value enumerator + // CHECK-NOTES: :8:12: note: enum is defined here + int C = int(); +} + +void f2() { + Enum1 A{}; + // CHECK-NOTES: :[[@LINE-1]]:10: warning: enum value of type 'Enum1' initialized with invalid value of 0, enum doesn't have a zero-value enumerator + // CHECK-NOTES: :8:12: note: enum is defined here + Enum1 B = Enum1(); + // CHECK-NOTES: :[[@LINE-1]]:13: warning: enum value of type 'Enum1' initialized with invalid value of 0, enum doesn't have a zero-value enumerator + // CHECK-NOTES: :8:12: note: enum is defined here + Enum1 C[5] = {{}}; + // CHECK-NOTES: :[[@LINE-1]]:16: warning: enum value of type 'Enum1' initialized with invalid value of 0, enum doesn't have a zero-value enumerator + // CHECK-NOTES: :8:12: note: enum is defined here + // CHECK-NOTES: :[[@LINE-3]]:17: warning: enum value of type 'Enum1' initialized with invalid value of 0, enum doesn't have a zero-value enumerator + // CHECK-NOTES: :8:12: note: enum is defined here + Enum1 D[5] = {}; // FIMXE: warn for this? + // CHECK-NOTES: :[[@LINE-1]]:16: warning: enum value of type 'Enum1' initialized with invalid value of 0, enum doesn't have a zero-value enumerator + // CHECK-NOTES: :8:12: note: enum is defined here +} + +struct S1 { + Enum1 E_1{}; + // CHECK-NOTES: :[[@LINE-1]]:12: warning: enum value of type 'Enum1' initialized with invalid value of 0, enum doesn't have a zero-value enumerator + // CHECK-NOTES: :8:12: note: enum is defined here + Enum1 E_2 = Enum1(); + // CHECK-NOTES: :[[@LINE-1]]:15: warning: enum value of type 'Enum1' initialized with invalid value of 0, enum doesn't have a zero-value enumerator + // CHECK-NOTES: :8:12: note: enum is defined here + Enum1 E_3; + Enum1 E_4; + Enum1 E_5; + + S1() : + E_3{}, + // CHECK-NOTES: :[[@LINE-1]]:8: warning: enum value of type 'Enum1' initialized with invalid value of 0, enum doesn't have a zero-value enumerator + // CHECK-NOTES: :8:12: note: enum is defined here + E_4(), + // CHECK-NOTES: :[[@LINE-1]]:8: warning: enum value of type 'Enum1' initialized with invalid value of 0, enum doesn't have a zero-value enumerator + // CHECK-NOTES: :8:12: note: enum is defined here + E_5{Enum1::B} + {} +}; + +struct S2 { + Enum0 X; + Enum1 Y; + Enum2 Z; +}; + +struct S3 { + S2 X; + int Y; +}; + +struct S4 : public S3 { + int Z; +}; + +struct S5 { + S2 X[3]; + int Y; +}; + +S2 VarS2{}; +// CHECK-NOTES: :[[@LINE-1]]:9: warning: enum value of type 'Enum1' initialized with invalid value of 0 +// CHECK-NOTES: :8:12: note: enum is defined here +// CHECK-NOTES: :[[@LINE-3]]:9: warning: enum value of type 'Enum2' initialized with invalid value of 0 +// CHECK-NOTES: :13:6: note: enum is defined here +S3 VarS3{}; +// CHECK-NOTES: :[[@LINE-1]]:10: warning: enum value of type 'Enum1' initialized with invalid value of 0 +// CHECK-NOTES: :8:12: note: enum is defined here +// CHECK-NOTES: :[[@LINE-3]]:10: warning: enum value of type 'Enum2' initialized with invalid value of 0 +// CHECK-NOTES: :13:6: note: enum is defined here +S4 VarS4{}; +// CHECK-NOTES: :[[@LINE-1]]:10: warning: enum value of type 'Enum1' initialized with invalid value of 0 +// CHECK-NOTES: :8:12: note: enum is defined here +// CHECK-NOTES: :[[@LINE-3]]:10: warning: enum value of type 'Enum2' initialized with invalid value of 0 +// CHECK-NOTES: :13:6: note: enum is defined here +S5 VarS5{}; +// CHECK-NOTES: :[[@LINE-1]]:10: warning: enum value of type 'Enum1' initialized with invalid value of 0 +// CHECK-NOTES: :8:12: note: enum is defined here + +enum class EnumFwd; + +EnumFwd Fwd{}; + +enum class EnumEmpty {}; + +EnumEmpty Empty{}; + +template<typename T> +struct Templ { + T Mem1{}; + // CHECK-NOTES: :[[@LINE-1]]:9: warning: enum value of type 'Enum1' initialized with invalid value of 0 + // CHECK-NOTES: :8:12: note: enum is defined here +}; + +Templ<Enum1> TemplVar; diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/signed-char-misuse-c23.c b/clang-tools-extra/test/clang-tidy/checkers/bugprone/signed-char-misuse-c23.c new file mode 100644 index 0000000..ad6e31d --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/signed-char-misuse-c23.c @@ -0,0 +1,201 @@ +// RUN: %check_clang_tidy %s bugprone-signed-char-misuse %t -- -- -std=c23 + +/////////////////////////////////////////////////////////////////// +/// Test cases correctly caught by the check. + +int SimpleVarDeclaration() { + signed char CCharacter = -5; + int NCharacter = CCharacter; + // CHECK-MESSAGES: [[@LINE-1]]:20: warning: 'signed char' to 'int' conversion; consider casting to 'unsigned char' first. [bugprone-signed-char-misuse] + + return NCharacter; +} + +int SimpleAssignment() { + signed char CCharacter = -5; + int NCharacter; + NCharacter = CCharacter; + // CHECK-MESSAGES: [[@LINE-1]]:16: warning: 'signed char' to 'int' conversion; consider casting to 'unsigned char' first. [bugprone-signed-char-misuse] + + return NCharacter; +} + +int NegativeConstValue() { + const signed char CCharacter = -5; + int NCharacter = CCharacter; + // CHECK-MESSAGES: [[@LINE-1]]:20: warning: 'signed char' to 'int' conversion; consider casting to 'unsigned char' first. [bugprone-signed-char-misuse] + + return NCharacter; +} + +int CharPointer(signed char *CCharacter) { + int NCharacter = *CCharacter; + // CHECK-MESSAGES: [[@LINE-1]]:20: warning: 'signed char' to 'int' conversion; consider casting to 'unsigned char' first. [bugprone-signed-char-misuse] + + return NCharacter; +} + +int SignedUnsignedCharEquality(signed char SCharacter) { + unsigned char USCharacter = 'a'; + if (SCharacter == USCharacter) // CHECK-MESSAGES: [[@LINE]]:7: warning: comparison between 'signed char' and 'unsigned char' [bugprone-signed-char-misuse] + return 1; + return 0; +} + +int SignedUnsignedCharIneqiality(signed char SCharacter) { + unsigned char USCharacter = 'a'; + if (SCharacter != USCharacter) // CHECK-MESSAGES: [[@LINE]]:7: warning: comparison between 'signed char' and 'unsigned char' [bugprone-signed-char-misuse] + return 1; + return 0; +} + +int CompareWithNonAsciiConstant(unsigned char USCharacter) { + const signed char SCharacter = -5; + if (USCharacter == SCharacter) // CHECK-MESSAGES: [[@LINE]]:7: warning: comparison between 'signed char' and 'unsigned char' [bugprone-signed-char-misuse] + return 1; + return 0; +} + +int CompareWithUnsignedNonAsciiConstant(signed char SCharacter) { + const unsigned char USCharacter = 128; + if (USCharacter == SCharacter) // CHECK-MESSAGES: [[@LINE]]:7: warning: comparison between 'signed char' and 'unsigned char' [bugprone-signed-char-misuse] + return 1; + return 0; +} + +/////////////////////////////////////////////////////////////////// +/// Test cases correctly ignored by the check. + +// Enum with a fixed underlying type of signed char. +enum EType1 : signed char { + EType1_M128 = -128, + EType1_1 = 1, +}; + +enum EType1 es1_1 = EType1_M128; +enum EType1 es1_2 = EType1_1; +enum EType1 es1_3 = -128; + +void assign(enum EType1 *es) { + *es = EType1_M128; +} + +// Type aliased enum with a fixed underlying type of signed char. +typedef signed char int8_t; +typedef enum EType2 : int8_t { + EType2_M128 = -128, + EType2_1 = 1, +} EType2_t; + +EType2_t es2_1 = EType2_M128; +EType2_t es2_2 = EType2_1; +EType2_t es2_3 = -128; + +// Enum with a fixed underlying type of unsigned char. +enum EType3 : unsigned char { + EType3_1 = 1, + EType3_128 = 128, +}; + +enum EType3 es3_1 = EType3_1; +enum EType3 es3_2 = EType3_128; +enum EType3 es3_3 = 128; + + +int UnsignedCharCast() { + unsigned char CCharacter = 'a'; + int NCharacter = CCharacter; + + return NCharacter; +} + +int PositiveConstValue() { + const signed char CCharacter = 5; + int NCharacter = CCharacter; + + return NCharacter; +} + +// signed char -> integer cast is not the direct child of declaration expression. +int DescendantCast() { + signed char CCharacter = 'a'; + int NCharacter = 10 + CCharacter; + + return NCharacter; +} + +// signed char -> integer cast is not the direct child of assignment expression. +int DescendantCastAssignment() { + signed char CCharacter = 'a'; + int NCharacter; + NCharacter = 10 + CCharacter; + + return NCharacter; +} + +// bool is an integer type in clang; make sure to ignore it. +bool BoolVarDeclaration() { + signed char CCharacter = 'a'; + bool BCharacter = CCharacter == 'b'; + + return BCharacter; +} + +// bool is an integer type in clang; make sure to ignore it. +bool BoolAssignment() { + signed char CCharacter = 'a'; + bool BCharacter; + BCharacter = CCharacter == 'b'; + + return BCharacter; +} + +// char is an integer type in clang; make sure to ignore it. +unsigned char CharToCharCast() { + signed char SCCharacter = 'a'; + unsigned char USCharacter; + USCharacter = SCCharacter; + + return USCharacter; +} + +int SameCharTypeComparison(signed char SCharacter) { + signed char SCharacter2 = 'a'; + if (SCharacter == SCharacter2) + return 1; + return 0; +} + +int SameCharTypeComparison2(unsigned char USCharacter) { + unsigned char USCharacter2 = 'a'; + if (USCharacter == USCharacter2) + return 1; + return 0; +} + +int CharIntComparison(signed char SCharacter) { + int ICharacter = 10; + if (SCharacter == ICharacter) + return 1; + return 0; +} + +int CompareWithAsciiLiteral(unsigned char USCharacter) { + if (USCharacter == 'x') + return 1; + return 0; +} + +int CompareWithAsciiConstant(unsigned char USCharacter) { + const signed char SCharacter = 'a'; + if (USCharacter == SCharacter) + return 1; + return 0; +} + +int CompareWithUnsignedAsciiConstant(signed char SCharacter) { + const unsigned char USCharacter = 'a'; + if (USCharacter == SCharacter) + return 1; + return 0; +} diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/unhandled-self-assignment.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/unhandled-self-assignment.cpp index 8610393..c2a8ddc 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/unhandled-self-assignment.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/unhandled-self-assignment.cpp @@ -28,6 +28,13 @@ template <class T> class auto_ptr { }; +namespace pmr { + template <typename TYPE = void> + class allocator {}; +} + +struct allocator_arg_t {} allocator_arg; + } // namespace std void assert(int expression){}; @@ -229,6 +236,122 @@ bool operator!=(Foo2 &, Foo2 &) { }; } +// Missing call to `swap` function +class AllocatorAwareClassNoSwap { + // pointer member to trigger bugprone-unhandled-self-assignment + void *foo = nullptr; + + public: + using allocator_type = std::pmr::allocator<>; + + AllocatorAwareClassNoSwap(const AllocatorAwareClassNoSwap& other) { + } + + AllocatorAwareClassNoSwap(const AllocatorAwareClassNoSwap& other, const allocator_type& alloc) { + } + + AllocatorAwareClassNoSwap& operator=(const AllocatorAwareClassNoSwap& other) { + // CHECK-MESSAGES: [[@LINE-1]]:32: warning: operator=() does not handle self-assignment properly [bugprone-unhandled-self-assignment] + AllocatorAwareClassNoSwap tmp(other, get_allocator()); + return *this; + } + + allocator_type get_allocator() const { + return allocator_type(); + } +}; + +// "Wrong" type is passed to member `swap` function +class AllocatorAwareClassSwapWrongArgType { + // pointer member to trigger bugprone-unhandled-self-assignment + void *foo = nullptr; + + public: + using allocator_type = std::pmr::allocator<>; + + AllocatorAwareClassSwapWrongArgType(const AllocatorAwareClassSwapWrongArgType& other) { + } + + AllocatorAwareClassSwapWrongArgType(const AllocatorAwareClassSwapWrongArgType& other, const allocator_type& alloc) { + } + + AllocatorAwareClassSwapWrongArgType& operator=(const AllocatorAwareClassSwapWrongArgType& other) { + // CHECK-MESSAGES: [[@LINE-1]]:42: warning: operator=() does not handle self-assignment properly [bugprone-unhandled-self-assignment] + int tmp = 0; + swap(tmp); + + return *this; + } + + void swap(int&) noexcept { + } + + allocator_type get_allocator() const { + return allocator_type(); + } +}; + + +// Making ADL `swap` call but with wrong argument type +class AllocatorAwareClassAdlSwapWrongArgType { + // pointer member to trigger bugprone-unhandled-self-assignment + void *foo = nullptr; + + public: + using allocator_type = std::pmr::allocator<>; + + AllocatorAwareClassAdlSwapWrongArgType(const AllocatorAwareClassAdlSwapWrongArgType& other) { + } + + AllocatorAwareClassAdlSwapWrongArgType(const AllocatorAwareClassAdlSwapWrongArgType& other, const allocator_type& alloc) { + } + + AllocatorAwareClassAdlSwapWrongArgType& operator=(const AllocatorAwareClassAdlSwapWrongArgType& other) { + // CHECK-MESSAGES: [[@LINE-1]]:45: warning: operator=() does not handle self-assignment properly [bugprone-unhandled-self-assignment] + int tmp = 0; + swap(*this, tmp); + + return *this; + } + + allocator_type get_allocator() const { + return allocator_type(); + } + + friend void swap(AllocatorAwareClassAdlSwapWrongArgType&, int&) { + } +}; + +// `this` isn't passed to `swap` +class AllocatorAwareClassAdlSwapWrongArgs { + // pointer member to trigger bugprone-unhandled-self-assignment + void *foo = nullptr; + + public: + using allocator_type = std::pmr::allocator<>; + + AllocatorAwareClassAdlSwapWrongArgs(const AllocatorAwareClassAdlSwapWrongArgs& other) { + } + + AllocatorAwareClassAdlSwapWrongArgs(const AllocatorAwareClassAdlSwapWrongArgs& other, const allocator_type& alloc) { + } + + AllocatorAwareClassAdlSwapWrongArgs& operator=(const AllocatorAwareClassAdlSwapWrongArgs& other) { + // CHECK-MESSAGES: [[@LINE-1]]:42: warning: operator=() does not handle self-assignment properly [bugprone-unhandled-self-assignment] + AllocatorAwareClassAdlSwapWrongArgs tmp1(other, get_allocator()); + AllocatorAwareClassAdlSwapWrongArgs tmp2(*this, get_allocator()); + swap(tmp1, tmp2); + return *this; + } + + allocator_type get_allocator() const { + return allocator_type(); + } + + friend void swap(AllocatorAwareClassAdlSwapWrongArgs&, AllocatorAwareClassAdlSwapWrongArgs&) { + } +}; + /////////////////////////////////////////////////////////////////// /// Test cases correctly ignored by the check. @@ -540,6 +663,89 @@ public: Uy *getUy() const { return Ptr2; } }; +// Support "extended" copy/move constructors +class AllocatorAwareClass { + // pointer member to trigger bugprone-unhandled-self-assignment + void *foo = nullptr; + + public: + using allocator_type = std::pmr::allocator<>; + + AllocatorAwareClass(const AllocatorAwareClass& other) { + } + + AllocatorAwareClass(const AllocatorAwareClass& other, const allocator_type& alloc) { + } + + AllocatorAwareClass& operator=(const AllocatorAwareClass& other) { + AllocatorAwareClass tmp(other, get_allocator()); + swap(tmp); + return *this; + } + + void swap(AllocatorAwareClass& other) noexcept { + } + + allocator_type get_allocator() const { + return allocator_type(); + } +}; + +// Support "extended" copy/move constructors + std::swap +class AllocatorAwareClassStdSwap { + // pointer member to trigger bugprone-unhandled-self-assignment + void *foo = nullptr; + + public: + using allocator_type = std::pmr::allocator<>; + + AllocatorAwareClassStdSwap(const AllocatorAwareClassStdSwap& other) { + } + + AllocatorAwareClassStdSwap(const AllocatorAwareClassStdSwap& other, const allocator_type& alloc) { + } + + AllocatorAwareClassStdSwap& operator=(const AllocatorAwareClassStdSwap& other) { + using std::swap; + + AllocatorAwareClassStdSwap tmp(other, get_allocator()); + swap(*this, tmp); + return *this; + } + + allocator_type get_allocator() const { + return allocator_type(); + } +}; + +// Support "extended" copy/move constructors + ADL swap +class AllocatorAwareClassAdlSwap { + // pointer member to trigger bugprone-unhandled-self-assignment + void *foo = nullptr; + + public: + using allocator_type = std::pmr::allocator<>; + + AllocatorAwareClassAdlSwap(const AllocatorAwareClassAdlSwap& other) { + } + + AllocatorAwareClassAdlSwap(const AllocatorAwareClassAdlSwap& other, const allocator_type& alloc) { + } + + AllocatorAwareClassAdlSwap& operator=(const AllocatorAwareClassAdlSwap& other) { + AllocatorAwareClassAdlSwap tmp(other, get_allocator()); + swap(*this, tmp); + return *this; + } + + allocator_type get_allocator() const { + return allocator_type(); + } + + friend void swap(AllocatorAwareClassAdlSwap&, AllocatorAwareClassAdlSwap&) { + } +}; + /////////////////////////////////////////////////////////////////// /// Test cases which should be caught by the check. diff --git a/clang-tools-extra/test/clang-tidy/checkers/llvm/use-new-mlir-op-builder.cpp b/clang-tools-extra/test/clang-tidy/checkers/llvm/use-new-mlir-op-builder.cpp new file mode 100644 index 0000000..0971a16 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/llvm/use-new-mlir-op-builder.cpp @@ -0,0 +1,76 @@ +// RUN: %check_clang_tidy --match-partial-fixes %s llvm-use-new-mlir-op-builder %t + +namespace mlir { +class Location {}; +class OpBuilder { +public: + template <typename OpTy, typename... Args> + OpTy create(Location location, Args &&...args) { + return OpTy(args...); + } + Location getUnknownLoc() { return Location(); } +}; +class ImplicitLocOpBuilder : public OpBuilder { +public: + template <typename OpTy, typename... Args> + OpTy create(Args &&...args) { + return OpTy(args...); + } +}; +struct ModuleOp { + ModuleOp() {} + static ModuleOp create(OpBuilder &builder, Location location) { + return ModuleOp(); + } +}; +struct NamedOp { + NamedOp(const char* name) {} + static NamedOp create(OpBuilder &builder, Location location, const char* name) { + return NamedOp(name); + } +}; +} // namespace mlir + +#define ASSIGN(A, B, C, D) C A = B.create<C>(B.getUnknownLoc(), D) + +template <typename T> +void g(mlir::OpBuilder &b) { + // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use 'OpType::create(builder, ...)' instead of 'builder.create<OpType>(...)' [llvm-use-new-mlir-op-builder] + // CHECK-FIXES: T::create(b, b.getUnknownLoc(), "gaz") + b.create<T>(b.getUnknownLoc(), "gaz"); +} + +void f() { + mlir::OpBuilder builder; + // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use 'OpType::create(builder, ...)' instead of 'builder.create<OpType>(...)' [llvm-use-new-mlir-op-builder] + // CHECK-FIXES: mlir:: ModuleOp::create(builder, builder.getUnknownLoc()) + builder.create<mlir:: ModuleOp>(builder.getUnknownLoc()); + + using mlir::NamedOp; + // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use 'OpType::create(builder, ...)' instead of 'builder.create<OpType>(...)' [llvm-use-new-mlir-op-builder] + // CHECK-FIXES: NamedOp::create(builder, builder.getUnknownLoc(), "baz") + builder.create<NamedOp>(builder.getUnknownLoc(), "baz"); + + // CHECK-MESSAGES: :[[@LINE+4]]:3: warning: use 'OpType::create(builder, ...)' instead of 'builder.create<OpType>(...)' [llvm-use-new-mlir-op-builder] + // CHECK-FIXES: NamedOp::create(builder, + // CHECK-FIXES: builder.getUnknownLoc(), + // CHECK-FIXES: "caz") + builder. + create<NamedOp>( + builder.getUnknownLoc(), + "caz"); + + // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: use 'OpType::create(builder, ...)' instead of 'builder.create<OpType>(...)' [llvm-use-new-mlir-op-builder] + ASSIGN(op, builder, NamedOp, "daz"); + + g<NamedOp>(builder); + + mlir::ImplicitLocOpBuilder ib; + // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use 'OpType::create(builder, ...)' instead of 'builder.create<OpType>(...)' [llvm-use-new-mlir-op-builder] + // CHECK-FIXES: mlir::ModuleOp::create(ib) + ib.create<mlir::ModuleOp>( ); + + // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use 'OpType::create(builder, ...)' instead of 'builder.create<OpType>(...)' [llvm-use-new-mlir-op-builder] + // CHECK-FIXES: mlir::OpBuilder().create<mlir::ModuleOp>(builder.getUnknownLoc()); + mlir::OpBuilder().create<mlir::ModuleOp>(builder.getUnknownLoc()); +} diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/header-include-cycle.cpp b/clang-tools-extra/test/clang-tidy/checkers/misc/header-include-cycle.cpp index d3c71ad..3694bdd 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/misc/header-include-cycle.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/misc/header-include-cycle.cpp @@ -1,15 +1,15 @@ -// RUN: rm -rf %T/misc-header-include-cycle-headers -// RUN: mkdir %T/misc-header-include-cycle-headers -// RUN: cp -r %S/Inputs/header-include-cycle* %T/misc-header-include-cycle-headers/ -// RUN: mkdir %T/misc-header-include-cycle-headers/system -// RUN: cp -r %S/Inputs/system/header-include-cycle* %T/misc-header-include-cycle-headers/system -// RUN: cp %s %T/header-include-cycle.cpp -// RUN: clang-tidy %T%{fs-sep}header-include-cycle.cpp -checks='-*,misc-header-include-cycle' -header-filter=.* \ +// RUN: rm -rf %t.dir/misc-header-include-cycle-headers +// RUN: mkdir -p %t.dir/misc-header-include-cycle-headers +// RUN: cp -r %S/Inputs/header-include-cycle* %t.dir/misc-header-include-cycle-headers/ +// RUN: mkdir %t.dir/misc-header-include-cycle-headers/system +// RUN: cp -r %S/Inputs/system/header-include-cycle* %t.dir/misc-header-include-cycle-headers/system +// RUN: cp %s %t.dir/header-include-cycle.cpp +// RUN: clang-tidy %t.dir%{fs-sep}header-include-cycle.cpp -checks='-*,misc-header-include-cycle' -header-filter=.* \ // RUN: -config="{CheckOptions: {misc-header-include-cycle.IgnoredFilesList: 'header-include-cycle.self-e.hpp'}}" \ -// RUN: -- -I%T%{fs-sep}misc-header-include-cycle-headers -isystem %T%{fs-sep}misc-header-include-cycle-headers%{fs-sep}system \ -// RUN: --include %T%{fs-sep}misc-header-include-cycle-headers%{fs-sep}header-include-cycle.self-i.hpp | FileCheck %s \ +// RUN: -- -I%t.dir%{fs-sep}misc-header-include-cycle-headers -isystem %t.dir%{fs-sep}misc-header-include-cycle-headers%{fs-sep}system \ +// RUN: --include %t.dir%{fs-sep}misc-header-include-cycle-headers%{fs-sep}header-include-cycle.self-i.hpp | FileCheck %s \ // RUN: -check-prefix=CHECK-MESSAGES "-implicit-check-not={{note|warning|error}}:" --dump-input=fail -// RUN: rm -rf %T/misc-header-include-cycle-headers +// RUN: rm -rf %t.dir/misc-header-include-cycle-headers #ifndef MAIN_GUARD #define MAIN_GUARD diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/unused-parameters.cpp b/clang-tools-extra/test/clang-tidy/checkers/misc/unused-parameters.cpp index f1918e9..c963cb5 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/misc/unused-parameters.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/misc/unused-parameters.cpp @@ -1,11 +1,11 @@ -// RUN: echo "static void staticFunctionHeader(int i) {;}" > %T/header.h -// RUN: echo "static void staticFunctionHeader(int /*i*/) {;}" > %T/header-fixed.h -// RUN: %check_clang_tidy --match-partial-fixes -std=c++11 %s misc-unused-parameters %t -- -header-filter='.*' -- -fno-delayed-template-parsing -// RUN: diff %T/header.h %T/header-fixed.h +// RUN: mkdir -p %t.dir +// RUN: echo "static void staticFunctionHeader(int i) {;}" > %t.dir/header.h +// RUN: echo "static void staticFunctionHeader(int /*i*/) {;}" > %t.dir/header-fixed.h +// RUN: %check_clang_tidy --match-partial-fixes -std=c++11 %s misc-unused-parameters %t.dir/code -- -header-filter='.*' -- -fno-delayed-template-parsing +// RUN: diff %t.dir/header.h %t.dir/header-fixed.h // FIXME: Make the test work in all language modes. #include "header.h" -// CHECK-MESSAGES: header.h:1:38: warning // Basic removal // ============= @@ -306,3 +306,5 @@ void test() { // Do not warn on naked functions. [[gnu::naked]] int nakedFunction(int a, float b, const char *c) { ; } __attribute__((naked)) void nakedFunction(int a, int b) { ; } + +// CHECK-MESSAGES: header.h:1:38: warning diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/concat-nested-namespaces.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/concat-nested-namespaces.cpp index a4f50dd..78adbeb 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/modernize/concat-nested-namespaces.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/concat-nested-namespaces.cpp @@ -1,10 +1,11 @@ -// RUN: cp %S/Inputs/concat-nested-namespaces/modernize-concat-nested-namespaces.h %T/modernize-concat-nested-namespaces.h -// RUN: %check_clang_tidy --match-partial-fixes -std=c++17 -check-suffix=NORMAL %s modernize-concat-nested-namespaces %t -- -header-filter=".*" -- -I %T -// RUN: FileCheck -input-file=%T/modernize-concat-nested-namespaces.h %S/Inputs/concat-nested-namespaces/modernize-concat-nested-namespaces.h -check-prefix=CHECK-FIXES +// RUN: mkdir -p %t.dir +// RUN: cp %S/Inputs/concat-nested-namespaces/modernize-concat-nested-namespaces.h %t.dir/modernize-concat-nested-namespaces.h +// RUN: %check_clang_tidy --match-partial-fixes -std=c++17 -check-suffix=NORMAL %s modernize-concat-nested-namespaces %t.dir/code -- -header-filter=".*" -- -I %t.dir +// RUN: FileCheck -input-file=%t.dir/modernize-concat-nested-namespaces.h %S/Inputs/concat-nested-namespaces/modernize-concat-nested-namespaces.h -check-prefix=CHECK-FIXES // Restore header file and re-run with c++20: -// RUN: cp %S/Inputs/concat-nested-namespaces/modernize-concat-nested-namespaces.h %T/modernize-concat-nested-namespaces.h -// RUN: %check_clang_tidy --match-partial-fixes -std=c++20 -check-suffixes=NORMAL,CPP20 %s modernize-concat-nested-namespaces %t -- -header-filter=".*" -- -I %T -// RUN: FileCheck -input-file=%T/modernize-concat-nested-namespaces.h %S/Inputs/concat-nested-namespaces/modernize-concat-nested-namespaces.h -check-prefix=CHECK-FIXES +// RUN: cp %S/Inputs/concat-nested-namespaces/modernize-concat-nested-namespaces.h %t.dir/modernize-concat-nested-namespaces.h +// RUN: %check_clang_tidy --match-partial-fixes -std=c++20 -check-suffixes=NORMAL,CPP20 %s modernize-concat-nested-namespaces %t.dir/code -- -header-filter=".*" -- -I %t.dir +// RUN: FileCheck -input-file=%t.dir/modernize-concat-nested-namespaces.h %S/Inputs/concat-nested-namespaces/modernize-concat-nested-namespaces.h -check-prefix=CHECK-FIXES #include "modernize-concat-nested-namespaces.h" // CHECK-MESSAGES-NORMAL-DAG: modernize-concat-nested-namespaces.h:1:1: warning: nested namespaces can be concatenated [modernize-concat-nested-namespaces] diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/pass-by-value-header.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/pass-by-value-header.cpp index 5d2f1af..461a637 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/modernize/pass-by-value-header.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/pass-by-value-header.cpp @@ -1,6 +1,7 @@ -// RUN: cp %S/Inputs/pass-by-value/header.h %T/pass-by-value-header.h -// RUN: clang-tidy %s -checks='-*,modernize-pass-by-value' -header-filter='.*' -fix -- -std=c++11 -I %T | FileCheck %s -check-prefix=CHECK-MESSAGES -implicit-check-not="{{warning|error}}:" -// RUN: FileCheck -input-file=%T/pass-by-value-header.h %s -check-prefix=CHECK-FIXES +// RUN: mkdir -p %t.dir +// RUN: cp %S/Inputs/pass-by-value/header.h %t.dir/pass-by-value-header.h +// RUN: clang-tidy %s -checks='-*,modernize-pass-by-value' -header-filter='.*' -fix -- -std=c++11 -I %t.dir | FileCheck %s -check-prefix=CHECK-MESSAGES -implicit-check-not="{{warning|error}}:" +// RUN: FileCheck -input-file=%t.dir/pass-by-value-header.h %s -check-prefix=CHECK-FIXES // FIXME: Make the test work in all language modes. #include "pass-by-value-header.h" diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/pass-by-value-multi-fixes.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/pass-by-value-multi-fixes.cpp index 238e445..b77c74b 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/modernize/pass-by-value-multi-fixes.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/pass-by-value-multi-fixes.cpp @@ -1,12 +1,13 @@ -// RUN: cat %S/Inputs/pass-by-value/header-with-fix.h > %T/pass-by-value-header-with-fix.h -// RUN: sed -e 's#//.*$##' %s > %t.cpp -// RUN: clang-tidy %t.cpp -checks='-*,modernize-pass-by-value' -header-filter='.*' -fix -- -std=c++11 -I %T | FileCheck %s -check-prefix=CHECK-MESSAGES -implicit-check-not="{{warning|error}}:" -// RUN: FileCheck -input-file=%t.cpp %s -check-prefix=CHECK-FIXES -// RUN: FileCheck -input-file=%T/pass-by-value-header-with-fix.h %s -check-prefix=CHECK-HEADER-FIXES +// RUN: mkdir -p %t.dir +// RUN: cat %S/Inputs/pass-by-value/header-with-fix.h > %t.dir/pass-by-value-header-with-fix.h +// RUN: sed -e 's#//.*$##' %s > %t.dir/code.cpp +// RUN: clang-tidy %t.dir/code.cpp -checks='-*,modernize-pass-by-value' -header-filter='.*' -fix -- -std=c++11 -I %t.dir | FileCheck %s -check-prefix=CHECK-MESSAGES -implicit-check-not="{{warning|error}}:" +// RUN: FileCheck -input-file=%t.dir/code.cpp %s -check-prefix=CHECK-FIXES +// RUN: FileCheck -input-file=%t.dir/pass-by-value-header-with-fix.h %s -check-prefix=CHECK-HEADER-FIXES #include "pass-by-value-header-with-fix.h" // CHECK-HEADER-FIXES: Foo(S s); Foo::Foo(const S &s) : s(s) {} -// CHECK-MESSAGES: :9:10: warning: pass by value and use std::move [modernize-pass-by-value] +// CHECK-MESSAGES: :10:10: warning: pass by value and use std::move [modernize-pass-by-value] // CHECK-FIXES: #include <utility> // CHECK-FIXES: Foo::Foo(S s) : s(std::move(s)) {} diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp index cdadeed..88e0636 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp @@ -224,3 +224,55 @@ std::array a{1,2,3}; std::array<int,2> b{10, 11}; using array = std::array<int, 2>; array c{10, 11}; + +struct S16 { + int a; + int b; +}; + +using S17 = S16; + +S17 s171{1, 2}; +// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use designated initializer list to initialize 'S17' (aka 'S16') [modernize-use-designated-initializers] +// CHECK-MESSAGES: :[[@LINE-9]]:1: note: aggregate type is defined here +// CHECK-FIXES: S17 s171{.a=1, .b=2}; +// CHECK-MESSAGES-POD: :[[@LINE-4]]:9: warning: use designated initializer list to initialize 'S17' (aka 'S16') [modernize-use-designated-initializers] +// CHECK-MESSAGES-POD: :[[@LINE-12]]:1: note: aggregate type is defined here +// CHECK-FIXES-POD: S17 s171{.a=1, .b=2}; + +S17 s172{.a=1, 2}; +// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: use designated init expression to initialize field 'b' [modernize-use-designated-initializers] +// CHECK-MESSAGES-POD: :[[@LINE-2]]:16: warning: use designated init expression to initialize field 'b' [modernize-use-designated-initializers] +// CHECK-FIXES: S17 s172{.a=1, .b=2}; + +S17 s173{.a=1, .b=2}; // no issue + +typedef S16 S18; + +S18 s181{1, 2}; +// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use designated initializer list to initialize 'S18' (aka 'S16') [modernize-use-designated-initializers] +// CHECK-MESSAGES-POD: :[[@LINE-2]]:9: warning: use designated initializer list to initialize 'S18' (aka 'S16') [modernize-use-designated-initializers] + +S18 s182{1, .b=2}; +// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use designated init expression to initialize field 'a' [modernize-use-designated-initializers] +// CHECK-MESSAGES-POD: :[[@LINE-2]]:10: warning: use designated init expression to initialize field 'a' [modernize-use-designated-initializers] +// CHECK-FIXES: S18 s182{.a=1, .b=2}; + +S18 s183{.a=1, .b=2}; // no issue + +struct S19 { + int i; + S17 s17; + S18 s18; +}; + +S19 s191{1, {2, .b=3}, {4, 5}}; +// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use designated initializer list to initialize 'S19' [modernize-use-designated-initializers] +// CHECK-MESSAGES: :[[@LINE-8]]:1: note: aggregate type is defined here +// CHECK-MESSAGES: :[[@LINE-3]]:14: warning: use designated init expression to initialize field 'a' [modernize-use-designated-initializers] +// CHECK-MESSAGES: :[[@LINE-4]]:24: warning: use designated initializer list to initialize 'S18' (aka 'S16') [modernize-use-designated-initializers] +// CHECK-MESSAGES-POD: :[[@LINE-5]]:9: warning: use designated initializer list to initialize 'S19' [modernize-use-designated-initializers] +// CHECK-MESSAGES-POD: :[[@LINE-12]]:1: note: aggregate type is defined here +// CHECK-MESSAGES-POD: :[[@LINE-7]]:14: warning: use designated init expression to initialize field 'a' [modernize-use-designated-initializers] +// CHECK-MESSAGES-POD: :[[@LINE-8]]:24: warning: use designated initializer list to initialize 'S18' (aka 'S16') [modernize-use-designated-initializers] +// CHECK-FIXES: S19 s191{.i=1, .s17={.a=2, .b=3}, .s18={.a=4, .b=5}}; diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-format-custom.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-format-custom.cpp index 7da0bb0..0f3458e 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-format-custom.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-format-custom.cpp @@ -2,7 +2,7 @@ // RUN: -std=c++20 %s modernize-use-std-format %t -- \ // RUN: -config="{CheckOptions: { \ // RUN: modernize-use-std-format.StrictMode: true, \ -// RUN: modernize-use-std-format.StrFormatLikeFunctions: '::strprintf; mynamespace::strprintf2; bad_format_type_strprintf', \ +// RUN: modernize-use-std-format.StrFormatLikeFunctions: '::strprintf; mynamespace::strprintf2; any_format_type_strprintf', \ // RUN: modernize-use-std-format.ReplacementFormatFunction: 'fmt::format', \ // RUN: modernize-use-std-format.FormatHeader: '<fmt/core.h>' \ // RUN: }}" \ @@ -10,7 +10,7 @@ // RUN: %check_clang_tidy -check-suffixes=,NOTSTRICT \ // RUN: -std=c++20 %s modernize-use-std-format %t -- \ // RUN: -config="{CheckOptions: { \ -// RUN: modernize-use-std-format.StrFormatLikeFunctions: '::strprintf; mynamespace::strprintf2; bad_format_type_strprintf', \ +// RUN: modernize-use-std-format.StrFormatLikeFunctions: '::strprintf; mynamespace::strprintf2; any_format_type_strprintf', \ // RUN: modernize-use-std-format.ReplacementFormatFunction: 'fmt::format', \ // RUN: modernize-use-std-format.FormatHeader: '<fmt/core.h>' \ // RUN: }}" \ @@ -56,12 +56,17 @@ std::string A(const std::string &in) struct S { S(...); }; -std::string bad_format_type_strprintf(const S &, ...); +std::string any_format_type_strprintf(const S &, ...); -std::string unsupported_format_parameter_type() +void unsupported_format_parameter_types() { // No fixes here because the format parameter of the function called is not a // string. - return bad_format_type_strprintf(""); -// CHECK-MESSAGES: [[@LINE-1]]:10: warning: unable to use 'fmt::format' instead of 'bad_format_type_strprintf' because first argument is not a narrow string literal [modernize-use-std-format] + auto s1 = any_format_type_strprintf(L""); + auto s2 = any_format_type_strprintf(42); + + // But if we do pass a character string then that ought to be acceptable. + auto s3 = any_format_type_strprintf("Hello %s", "world"); + // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use 'fmt::format' instead of 'any_format_type_strprintf' [modernize-use-std-format] + // CHECK-FIXES: auto s3 = fmt::format("Hello {}", "world"); } diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-format.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-format.cpp index 1a241e3..ea97d5b 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-format.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-format.cpp @@ -16,8 +16,8 @@ namespace absl { -template <typename S, typename... Args> -std::string StrFormat(const S &format, const Args&... args); +template <typename... Args> +std::string StrFormat(const std::string_view &format, const Args&... args); } // namespace absl template <typename T> diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print-absl.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print-absl.cpp index 83fbd2e..3dab6e9 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print-absl.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print-absl.cpp @@ -9,15 +9,15 @@ #include <cstdio> #include <string.h> +#include <string> namespace absl { -// Use const char * for the format since the real type is hard to mock up. template <typename... Args> -int PrintF(const char *format, const Args&... args); +int PrintF(const std::string_view &format, const Args&... args); template <typename... Args> -int FPrintF(FILE* output, const char *format, const Args&... args); +int FPrintF(FILE* output, const std::string_view &format, const Args&... args); } void printf_simple() { diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print-custom.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print-custom.cpp index 687b8c0..2c6a651 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print-custom.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-print-custom.cpp @@ -1,8 +1,8 @@ // RUN: %check_clang_tidy -std=c++23 %s modernize-use-std-print %t -- \ // RUN: -config="{CheckOptions: \ // RUN: { \ -// RUN: modernize-use-std-print.PrintfLikeFunctions: 'unqualified_printf;::myprintf; mynamespace::myprintf2; bad_format_type_printf; fmt::printf', \ -// RUN: modernize-use-std-print.FprintfLikeFunctions: '::myfprintf; mynamespace::myfprintf2; bad_format_type_fprintf; fmt::fprintf' \ +// RUN: modernize-use-std-print.PrintfLikeFunctions: 'unqualified_printf;::myprintf; mynamespace::myprintf2; any_format_type_printf; fmt::printf', \ +// RUN: modernize-use-std-print.FprintfLikeFunctions: '::myfprintf; mynamespace::myfprintf2; any_format_type_fprintf; fmt::fprintf' \ // RUN: } \ // RUN: }" \ // RUN: -- -isystem %clang_tidy_headers @@ -98,18 +98,25 @@ void wide_string_not_supported() { struct S { S(...) {} }; -int bad_format_type_printf(const S &, ...); -int bad_format_type_fprintf(FILE *, const S &, ...); +int any_format_type_printf(const S &, ...); +int any_format_type_fprintf(FILE *, const S &, ...); void unsupported_format_parameter_type() { // No fixes here because the format parameter of the function called is not a // string. - bad_format_type_printf("Hello %s", "world"); -// CHECK-MESSAGES: [[@LINE-1]]:3: warning: unable to use 'std::print' instead of 'bad_format_type_printf' because first argument is not a narrow string literal [modernize-use-std-print] - - bad_format_type_fprintf(stderr, "Hello %s", "world"); -// CHECK-MESSAGES: [[@LINE-1]]:3: warning: unable to use 'std::print' instead of 'bad_format_type_fprintf' because first argument is not a narrow string literal [modernize-use-std-print] + any_format_type_printf(L"Hello %s", "world"); + any_format_type_fprintf(stderr, L"Hello %s", "world"); + any_format_type_printf(42); + any_format_type_fprintf(stderr, 42L); + + // But if we do pass a character string then that ought to be acceptable. + any_format_type_printf("Hello %s\n", "world"); + // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'any_format_type_printf' [modernize-use-std-print] + // CHECK-FIXES: std::println("Hello {}", "world"); + any_format_type_fprintf(stderr, "Hello %s\n", "world"); + // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'any_format_type_fprintf' [modernize-use-std-print] + // CHECK-FIXES: std::println(stderr, "Hello {}", "world"); } namespace fmt { diff --git a/clang-tools-extra/test/clang-tidy/checkers/portability/restrict-system-includes-transitive.cpp b/clang-tools-extra/test/clang-tidy/checkers/portability/restrict-system-includes-transitive.cpp index 744f45f..ff7c66b 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/portability/restrict-system-includes-transitive.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/portability/restrict-system-includes-transitive.cpp @@ -1,12 +1,12 @@ -// RUN: rm -rf %T/Headers -// RUN: mkdir %T/Headers -// RUN: cp -r %S/Inputs/restrict-system-includes %T/Headers/portability-restrict-system-includes +// RUN: rm -rf %t.dir/Headers +// RUN: mkdir -p %t.dir/Headers +// RUN: cp -r %S/Inputs/restrict-system-includes %t.dir/Headers/portability-restrict-system-includes // RUN: %check_clang_tidy -std=c++11 %s portability-restrict-system-includes %t \ // RUN: -- -config="{CheckOptions: {portability-restrict-system-includes.Includes: 'transitive.h,s.h'}}" \ // RUN: -system-headers -header-filter=.* \ -// RUN: -- -I %T/Headers/portability-restrict-system-includes -isystem %T/Headers/portability-restrict-system-includes/system -// RUN: FileCheck -input-file=%T/Headers/portability-restrict-system-includes/transitive2.h %s -check-prefix=CHECK-FIXES -// RUN: rm -rf %T/Headers +// RUN: -- -I %t.dir/Headers/portability-restrict-system-includes -isystem %t.dir/Headers/portability-restrict-system-includes/system +// RUN: FileCheck -input-file=%t.dir/Headers/portability-restrict-system-includes/transitive2.h %s -check-prefix=CHECK-FIXES +// RUN: rm -rf %t.dir/Headers // FIXME: Make the test work in all language modes. // transitive.h includes <r.h> and <t.h> diff --git a/clang-tools-extra/test/clang-tidy/checkers/portability/template-virtual-member-function.cpp b/clang-tools-extra/test/clang-tidy/checkers/portability/template-virtual-member-function.cpp index 94786ae..2a67b79 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/portability/template-virtual-member-function.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/portability/template-virtual-member-function.cpp @@ -171,3 +171,20 @@ struct NoInstantiation<int, U>{ }; }; } // namespace PartialSpecializationNoInstantiation + +namespace PureVirtual { + +template<typename T> +struct Base { + virtual void foo() = 0; +}; + +struct Derived : public Base<int> { + void foo() {} +}; + +void test() { + Derived{}.foo(); +} + +} diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-naming-symlink.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-naming-symlink.cpp index 34dc340..7c99f70 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-naming-symlink.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-naming-symlink.cpp @@ -2,11 +2,12 @@ // in the header file so it fails if runs multiple times with different // `-std` flags as check_clang_tidy doesn by default. // -// RUN: rm -rf %T/symlink -// RUN: cp -r %S/Inputs/identifier-naming/symlink %T/symlink -// RUN: mkdir -p %T/symlink/build -// RUN: ln -s %T/symlink/include/test.h %T/symlink/build/test.h -// RUN: %check_clang_tidy -std=c++20 %s readability-identifier-naming %t -- --header-filter="test.h" --config-file=%S/Inputs/identifier-naming/symlink/include/.clang-tidy -- -I %T/symlink/build +// RUN: rm -rf %t.dir +// RUN: mkdir -p %t.dir +// RUN: cp -r %S/Inputs/identifier-naming/symlink %t.dir/symlink +// RUN: mkdir -p %t.dir/symlink/build +// RUN: ln -s %t.dir/symlink/include/test.h %t.dir/symlink/build/test.h +// RUN: %check_clang_tidy -std=c++20 %s readability-identifier-naming %t.dir -- --header-filter="test.h" --config-file=%S/Inputs/identifier-naming/symlink/include/.clang-tidy -- -I %t.dir/symlink/build // UNSUPPORTED: system-windows #include "test.h" diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/qualified-auto.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/qualified-auto.cpp index 77afdca..83b7b1d 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/readability/qualified-auto.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/qualified-auto.cpp @@ -2,6 +2,11 @@ // RUN: -config='{CheckOptions: { \ // RUN: readability-qualified-auto.AllowedTypes: "[iI]terator$;my::ns::Ignored1;std::array<.*>::Ignored2;MyIgnoredPtr" \ // RUN: }}' +// RUN: %check_clang_tidy %s readability-qualified-auto %t \ +// RUN: -config='{CheckOptions: { \ +// RUN: readability-qualified-auto.AllowedTypes: "[iI]terator$;my::ns::Ignored1;std::array<.*>::Ignored2;MyIgnoredPtr", \ +// RUN: readability-qualified-auto.IgnoreAliasing: false \ +// RUN: }}' -check-suffix=ALIAS -- namespace typedefs { typedef int *MyPtr; @@ -10,22 +15,36 @@ typedef const int *CMyPtr; typedef const int &CMyRef; MyPtr getPtr(); +MyPtr* getPtrPtr(); MyRef getRef(); CMyPtr getCPtr(); +CMyPtr* getCPtrPtr(); CMyRef getCRef(); void foo() { auto TdNakedPtr = getPtr(); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'auto TdNakedPtr' can be declared as 'auto *TdNakedPtr' // CHECK-FIXES: {{^}} auto *TdNakedPtr = getPtr(); + auto TdNakedPtrPtr = getPtrPtr(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'auto TdNakedPtrPtr' can be declared as 'auto *TdNakedPtrPtr' + // CHECK-FIXES: {{^}} auto *TdNakedPtrPtr = getPtrPtr(); + // CHECK-MESSAGES-ALIAS: :[[@LINE-3]]:3: warning: 'auto TdNakedPtrPtr' can be declared as 'auto *TdNakedPtrPtr' + // CHECK-FIXES-ALIAS: {{^}} auto *TdNakedPtrPtr = getPtrPtr(); auto &TdNakedRef = getRef(); auto TdNakedRefDeref = getRef(); auto TdNakedCPtr = getCPtr(); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'auto TdNakedCPtr' can be declared as 'const auto *TdNakedCPtr' // CHECK-FIXES: {{^}} const auto *TdNakedCPtr = getCPtr(); + auto TdNakedCPtrPtr = getCPtrPtr(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'auto TdNakedCPtrPtr' can be declared as 'auto *TdNakedCPtrPtr' + // CHECK-FIXES: {{^}} auto *TdNakedCPtrPtr = getCPtrPtr(); + // CHECK-MESSAGES-ALIAS: :[[@LINE-3]]:3: warning: 'auto TdNakedCPtrPtr' can be declared as 'auto *TdNakedCPtrPtr' + // CHECK-FIXES-ALIAS: {{^}} auto *TdNakedCPtrPtr = getCPtrPtr(); auto &TdNakedCRef = getCRef(); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'auto &TdNakedCRef' can be declared as 'const auto &TdNakedCRef' // CHECK-FIXES: {{^}} const auto &TdNakedCRef = getCRef(); + // CHECK-MESSAGES-ALIAS: :[[@LINE-3]]:3: warning: 'auto &TdNakedCRef' can be declared as 'const auto &TdNakedCRef' + // CHECK-FIXES-ALIAS: {{^}} const auto &TdNakedCRef = getCRef(); auto TdNakedCRefDeref = getCRef(); } @@ -38,6 +57,7 @@ using CMyPtr = const int *; using CMyRef = const int &; MyPtr getPtr(); +MyPtr* getPtrPtr(); MyRef getRef(); CMyPtr getCPtr(); CMyRef getCRef(); @@ -46,6 +66,11 @@ void foo() { auto UNakedPtr = getPtr(); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'auto UNakedPtr' can be declared as 'auto *UNakedPtr' // CHECK-FIXES: {{^}} auto *UNakedPtr = getPtr(); + auto UNakedPtrPtr = getPtrPtr(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'auto UNakedPtrPtr' can be declared as 'auto *UNakedPtrPtr' + // CHECK-FIXES: {{^}} auto *UNakedPtrPtr = getPtrPtr(); + // CHECK-MESSAGES-ALIAS: :[[@LINE-3]]:3: warning: 'auto UNakedPtrPtr' can be declared as 'auto *UNakedPtrPtr' + // CHECK-FIXES-ALIAS: {{^}} auto *UNakedPtrPtr = getPtrPtr(); auto &UNakedRef = getRef(); auto UNakedRefDeref = getRef(); auto UNakedCPtr = getCPtr(); @@ -54,6 +79,8 @@ void foo() { auto &UNakedCRef = getCRef(); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'auto &UNakedCRef' can be declared as 'const auto &UNakedCRef' // CHECK-FIXES: {{^}} const auto &UNakedCRef = getCRef(); + // CHECK-MESSAGES-ALIAS: :[[@LINE-3]]:3: warning: 'auto &UNakedCRef' can be declared as 'const auto &UNakedCRef' + // CHECK-FIXES-ALIAS: {{^}} const auto &UNakedCRef = getCRef(); auto UNakedCRefDeref = getCRef(); } @@ -77,45 +104,67 @@ void foo() { auto NakedPtr = getIntPtr(); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'auto NakedPtr' can be declared as 'auto *NakedPtr' // CHECK-FIXES: {{^}} auto *NakedPtr = getIntPtr(); + // CHECK-MESSAGES-ALIAS: :[[@LINE-3]]:3: warning: 'auto NakedPtr' can be declared as 'auto *NakedPtr' + // CHECK-FIXES-ALIAS: {{^}} auto *NakedPtr = getIntPtr(); auto NakedCPtr = getCIntPtr(); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'auto NakedCPtr' can be declared as 'const auto *NakedCPtr' // CHECK-FIXES: {{^}} const auto *NakedCPtr = getCIntPtr(); + // CHECK-MESSAGES-ALIAS: :[[@LINE-3]]:3: warning: 'auto NakedCPtr' can be declared as 'const auto *NakedCPtr' + // CHECK-FIXES-ALIAS: {{^}} const auto *NakedCPtr = getCIntPtr(); const auto ConstPtr = getIntPtr(); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'const auto ConstPtr' can be declared as 'auto *const ConstPtr' // CHECK-FIXES: {{^}} auto *const ConstPtr = getIntPtr(); + // CHECK-MESSAGES-ALIAS: :[[@LINE-3]]:3: warning: 'const auto ConstPtr' can be declared as 'auto *const ConstPtr' + // CHECK-FIXES-ALIAS: {{^}} auto *const ConstPtr = getIntPtr(); const auto ConstCPtr = getCIntPtr(); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'const auto ConstCPtr' can be declared as 'const auto *const ConstCPtr' // CHECK-FIXES: {{^}} const auto *const ConstCPtr = getCIntPtr(); + // CHECK-MESSAGES-ALIAS: :[[@LINE-3]]:3: warning: 'const auto ConstCPtr' can be declared as 'const auto *const ConstCPtr' + // CHECK-FIXES-ALIAS: {{^}} const auto *const ConstCPtr = getCIntPtr(); volatile auto VolatilePtr = getIntPtr(); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'volatile auto VolatilePtr' can be declared as 'auto *volatile VolatilePtr' // CHECK-FIXES: {{^}} auto *volatile VolatilePtr = getIntPtr(); + // CHECK-MESSAGES-ALIAS: :[[@LINE-3]]:3: warning: 'volatile auto VolatilePtr' can be declared as 'auto *volatile VolatilePtr' + // CHECK-FIXES-ALIAS: {{^}} auto *volatile VolatilePtr = getIntPtr(); volatile auto VolatileCPtr = getCIntPtr(); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'volatile auto VolatileCPtr' can be declared as 'const auto *volatile VolatileCPtr' // CHECK-FIXES: {{^}} const auto *volatile VolatileCPtr = getCIntPtr(); + // CHECK-MESSAGES-ALIAS: :[[@LINE-3]]:3: warning: 'volatile auto VolatileCPtr' can be declared as 'const auto *volatile VolatileCPtr' + // CHECK-FIXES-ALIAS: {{^}} const auto *volatile VolatileCPtr = getCIntPtr(); auto *QualPtr = getIntPtr(); auto *QualCPtr = getCIntPtr(); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'auto *QualCPtr' can be declared as 'const auto *QualCPtr' // CHECK-FIXES: {{^}} const auto *QualCPtr = getCIntPtr(); + // CHECK-MESSAGES-ALIAS: :[[@LINE-3]]:3: warning: 'auto *QualCPtr' can be declared as 'const auto *QualCPtr' + // CHECK-FIXES-ALIAS: {{^}} const auto *QualCPtr = getCIntPtr(); auto *const ConstantQualCPtr = getCIntPtr(); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'auto *const ConstantQualCPtr' can be declared as 'const auto *const ConstantQualCPtr' // CHECK-FIXES: {{^}} const auto *const ConstantQualCPtr = getCIntPtr(); + // CHECK-MESSAGES-ALIAS: :[[@LINE-3]]:3: warning: 'auto *const ConstantQualCPtr' can be declared as 'const auto *const ConstantQualCPtr' + // CHECK-FIXES-ALIAS: {{^}} const auto *const ConstantQualCPtr = getCIntPtr(); auto *volatile VolatileQualCPtr = getCIntPtr(); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'auto *volatile VolatileQualCPtr' can be declared as 'const auto *volatile VolatileQualCPtr' // CHECK-FIXES: {{^}} const auto *volatile VolatileQualCPtr = getCIntPtr(); + // CHECK-MESSAGES-ALIAS: :[[@LINE-3]]:3: warning: 'auto *volatile VolatileQualCPtr' can be declared as 'const auto *volatile VolatileQualCPtr' + // CHECK-FIXES-ALIAS: {{^}} const auto *volatile VolatileQualCPtr = getCIntPtr(); const auto *ConstQualCPtr = getCIntPtr(); auto &Ref = *getIntPtr(); auto &CRef = *getCIntPtr(); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'auto &CRef' can be declared as 'const auto &CRef' // CHECK-FIXES: {{^}} const auto &CRef = *getCIntPtr(); + // CHECK-MESSAGES-ALIAS: :[[@LINE-3]]:3: warning: 'auto &CRef' can be declared as 'const auto &CRef' + // CHECK-FIXES-ALIAS: {{^}} const auto &CRef = *getCIntPtr(); const auto &ConstCRef = *getCIntPtr(); if (auto X = getCIntPtr()) { // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'auto X' can be declared as 'const auto *X' // CHECK-FIXES: {{^}} if (const auto *X = getCIntPtr()) { + // CHECK-MESSAGES-ALIAS: :[[@LINE-3]]:7: warning: 'auto X' can be declared as 'const auto *X' + // CHECK-FIXES-ALIAS: {{^}} if (const auto *X = getCIntPtr()) { } } @@ -153,6 +202,8 @@ void loopRef(std::vector<int> &Mutate, const std::vector<int> &Constant) { for (auto &Data : Constant) { // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: 'auto &Data' can be declared as 'const auto &Data' // CHECK-FIXES: {{^}} for (const auto &Data : Constant) { + // CHECK-MESSAGES-ALIAS: :[[@LINE-3]]:8: warning: 'auto &Data' can be declared as 'const auto &Data' + // CHECK-FIXES-ALIAS: {{^}} for (const auto &Data : Constant) { observe(Data); } } @@ -161,11 +212,15 @@ void loopPtr(const std::vector<int *> &Mutate, const std::vector<const int *> &C for (auto Data : Mutate) { // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: 'auto Data' can be declared as 'auto *Data' // CHECK-FIXES: {{^}} for (auto *Data : Mutate) { + // CHECK-MESSAGES-ALIAS: :[[@LINE-3]]:8: warning: 'auto Data' can be declared as 'auto *Data' + // CHECK-FIXES-ALIAS: {{^}} for (auto *Data : Mutate) { change(*Data); } for (auto Data : Constant) { // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: 'auto Data' can be declared as 'const auto *Data' // CHECK-FIXES: {{^}} for (const auto *Data : Constant) { + // CHECK-MESSAGES-ALIAS: :[[@LINE-3]]:8: warning: 'auto Data' can be declared as 'const auto *Data' + // CHECK-FIXES-ALIAS: {{^}} for (const auto *Data : Constant) { observe(*Data); } } @@ -175,12 +230,16 @@ void tempLoopPtr(std::vector<T *> &MutateTemplate, std::vector<const T *> &Const for (auto Data : MutateTemplate) { // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: 'auto Data' can be declared as 'auto *Data' // CHECK-FIXES: {{^}} for (auto *Data : MutateTemplate) { + // CHECK-MESSAGES-ALIAS: :[[@LINE-3]]:8: warning: 'auto Data' can be declared as 'auto *Data' + // CHECK-FIXES-ALIAS: {{^}} for (auto *Data : MutateTemplate) { change(*Data); } //FixMe for (auto Data : ConstantTemplate) { // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: 'auto Data' can be declared as 'const auto *Data' // CHECK-FIXES: {{^}} for (const auto *Data : ConstantTemplate) { + // CHECK-MESSAGES-ALIAS: :[[@LINE-3]]:8: warning: 'auto Data' can be declared as 'const auto *Data' + // CHECK-FIXES-ALIAS: {{^}} for (const auto *Data : ConstantTemplate) { observe(*Data); } } @@ -192,12 +251,16 @@ public: for (auto Data : MClassTemplate) { // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: 'auto Data' can be declared as 'auto *Data' // CHECK-FIXES: {{^}} for (auto *Data : MClassTemplate) { + // CHECK-MESSAGES-ALIAS: :[[@LINE-3]]:10: warning: 'auto Data' can be declared as 'auto *Data' + // CHECK-FIXES-ALIAS: {{^}} for (auto *Data : MClassTemplate) { change(*Data); } //FixMe for (auto Data : CClassTemplate) { // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: 'auto Data' can be declared as 'const auto *Data' // CHECK-FIXES: {{^}} for (const auto *Data : CClassTemplate) { + // CHECK-MESSAGES-ALIAS: :[[@LINE-3]]:10: warning: 'auto Data' can be declared as 'const auto *Data' + // CHECK-FIXES-ALIAS: {{^}} for (const auto *Data : CClassTemplate) { observe(*Data); } } @@ -223,21 +286,31 @@ void baz() { auto MyFunctionPtr = getPtrFunction(); // CHECK-MESSAGES-NOT: :[[@LINE-1]]:3: warning: 'auto MyFunctionPtr' can be declared as 'auto *MyFunctionPtr' // CHECK-FIXES-NOT: {{^}} auto *MyFunctionPtr = getPtrFunction(); + // CHECK-MESSAGES-NOT-ALIAS: :[[@LINE-1]]:3: warning: 'auto MyFunctionPtr' can be declared as 'auto *MyFunctionPtr' + // CHECK-FIXES-NOT-ALIAS: {{^}} auto *MyFunctionPtr = getPtrFunction(); auto MyFunctionVal = getValFunction(); // CHECK-MESSAGES-NOT: :[[@LINE-1]]:3: warning: 'auto MyFunctionVal' can be declared as 'auto *MyFunctionVal' // CHECK-FIXES-NOT: {{^}} auto *MyFunctionVal = getValFunction(); + // CHECK-MESSAGES-NOT-ALIAS: :[[@LINE-3]]:3: warning: 'auto MyFunctionVal' can be declared as 'auto *MyFunctionVal' + // CHECK-FIXES-NOT-ALIAS: {{^}} auto *MyFunctionVal = getValFunction(); auto LambdaTest = [] { return 0; }; // CHECK-MESSAGES-NOT: :[[@LINE-1]]:3: warning: 'auto LambdaTest' can be declared as 'auto *LambdaTest' // CHECK-FIXES-NOT: {{^}} auto *LambdaTest = [] { return 0; }; + // CHECK-MESSAGES-NOT-ALIAS: :[[@LINE-3]]:3: warning: 'auto LambdaTest' can be declared as 'auto *LambdaTest' + // CHECK-FIXES-NOT-ALIAS: {{^}} auto *LambdaTest = [] { return 0; }; auto LambdaTest2 = +[] { return 0; }; // CHECK-MESSAGES-NOT: :[[@LINE-1]]:3: warning: 'auto LambdaTest2' can be declared as 'auto *LambdaTest2' // CHECK-FIXES-NOT: {{^}} auto *LambdaTest2 = +[] { return 0; }; + // CHECK-MESSAGES-NOT-ALIAS: :[[@LINE-3]]:3: warning: 'auto LambdaTest2' can be declared as 'auto *LambdaTest2' + // CHECK-FIXES-NOT-ALIAS: {{^}} auto *LambdaTest2 = +[] { return 0; }; auto MyFunctionRef = *getPtrFunction(); // CHECK-MESSAGES-NOT: :[[@LINE-1]]:3: warning: 'auto MyFunctionRef' can be declared as 'auto *MyFunctionRef' // CHECK-FIXES-NOT: {{^}} auto *MyFunctionRef = *getPtrFunction(); + // CHECK-MESSAGES-NOT-ALIAS: :[[@LINE-3]]:3: warning: 'auto MyFunctionRef' can be declared as 'auto *MyFunctionRef' + // CHECK-FIXES-NOT-ALIAS: {{^}} auto *MyFunctionRef = *getPtrFunction(); auto &MyFunctionRef2 = *getPtrFunction(); } @@ -339,10 +412,14 @@ void ignored_types() { auto arr_not_ignored2 = new std::array<int, 4>::NotIgnored2(); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'auto arr_not_ignored2' can be declared as 'auto *arr_not_ignored2' // CHECK-FIXES: auto *arr_not_ignored2 = new std::array<int, 4>::NotIgnored2(); + // CHECK-MESSAGES-ALIAS: :[[@LINE-3]]:3: warning: 'auto arr_not_ignored2' can be declared as 'auto *arr_not_ignored2' + // CHECK-FIXES-ALIAS: auto *arr_not_ignored2 = new std::array<int, 4>::NotIgnored2(); auto not_ignored2 = new std::Ignored2(); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'auto not_ignored2' can be declared as 'auto *not_ignored2' // CHECK-FIXES: auto *not_ignored2 = new std::Ignored2(); + // CHECK-MESSAGES-ALIAS: :[[@LINE-3]]:3: warning: 'auto not_ignored2' can be declared as 'auto *not_ignored2' + // CHECK-FIXES-ALIAS: auto *not_ignored2 = new std::Ignored2(); auto ignored1 = new my::ns::Ignored1(); // CHECK-MESSAGES-NOT: warning: 'auto ignored1' can be declared as 'auto *ignored1' @@ -351,14 +428,20 @@ void ignored_types() { auto not_ignored1 = new my::ns::NotIgnored1(); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'auto not_ignored1' can be declared as 'auto *not_ignored1' // CHECK-FIXES: auto *not_ignored1 = new my::ns::NotIgnored1(); + // CHECK-MESSAGES-ALIAS: :[[@LINE-3]]:3: warning: 'auto not_ignored1' can be declared as 'auto *not_ignored1' + // CHECK-FIXES-ALIAS: auto *not_ignored1 = new my::ns::NotIgnored1(); auto not2_ignored1 = new my::ns::NotIgnored2(); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'auto not2_ignored1' can be declared as 'auto *not2_ignored1' // CHECK-FIXES: auto *not2_ignored1 = new my::ns::NotIgnored2(); + // CHECK-MESSAGES-ALIAS: :[[@LINE-3]]:3: warning: 'auto not2_ignored1' can be declared as 'auto *not2_ignored1' + // CHECK-FIXES-ALIAS: auto *not2_ignored1 = new my::ns::NotIgnored2(); auto not3_ignored1 = new my::Ignored1(); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'auto not3_ignored1' can be declared as 'auto *not3_ignored1' // CHECK-FIXES: auto *not3_ignored1 = new my::Ignored1(); + // CHECK-MESSAGES-ALIAS: :[[@LINE-3]]:3: warning: 'auto not3_ignored1' can be declared as 'auto *not3_ignored1' + // CHECK-FIXES-ALIAS: auto *not3_ignored1 = new my::Ignored1(); } template <typename T> diff --git a/clang-tools-extra/test/clang-tidy/infrastructure/clang-tidy-diff.cpp b/clang-tools-extra/test/clang-tidy/infrastructure/clang-tidy-diff.cpp index 2e18a43..25be90f 100644 --- a/clang-tools-extra/test/clang-tidy/infrastructure/clang-tidy-diff.cpp +++ b/clang-tools-extra/test/clang-tidy/infrastructure/clang-tidy-diff.cpp @@ -1,15 +1,19 @@ // REQUIRES: shell // RUN: sed 's/placeholder_for_f/f/' %s > %t.cpp // RUN: clang-tidy -checks=-*,modernize-use-override %t.cpp -- -std=c++11 | FileCheck -check-prefix=CHECK-SANITY %s -// RUN: not diff -U0 %s %t.cpp | %clang_tidy_diff -checks=-*,modernize-use-override -- -std=c++11 2>&1 | FileCheck %s +// RUN: not diff -U0 %s %t.cpp | %clang_tidy_diff -checks=-*,modernize-use-override -- -std=c++11 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-JMAX // RUN: not diff -U0 %s %t.cpp | %clang_tidy_diff -checks=-*,modernize-use-override -quiet -- -std=c++11 2>&1 | FileCheck -check-prefix=CHECK-QUIET %s -// RUN: mkdir -p %T/compilation-database-test/ -// RUN: echo '[{"directory": "%T", "command": "clang++ -o test.o -std=c++11 %t.cpp", "file": "%t.cpp"}]' > %T/compilation-database-test/compile_commands.json -// RUN: not diff -U0 %s %t.cpp | %clang_tidy_diff -checks=-*,modernize-use-override -path %T/compilation-database-test 2>&1 | FileCheck -check-prefix=CHECK %s +// RUN: mkdir -p %t.dir/compilation-database-test/ +// RUN: echo '[{"directory": "%t.dir", "command": "clang++ -o test.o -std=c++11 %t.cpp", "file": "%t.cpp"}]' > %t.dir/compilation-database-test/compile_commands.json +// RUN: not diff -U0 %s %t.cpp | %clang_tidy_diff -checks=-*,modernize-use-override -path %t.dir/compilation-database-test 2>&1 | FileCheck -check-prefix=CHECK %s + +// RUN: not diff -U0 %s %t.cpp | %clang_tidy_diff -checks=-*,modernize-use-override -j 1 -- -std=c++11 2>&1 | FileCheck %s --check-prefix=CHECK-J1 +// CHECK-J1: Running clang-tidy in 1 threads... struct A { virtual void f() {} virtual void g() {} }; +// CHECK-JMAX: Running clang-tidy in {{[1-9][0-9]*}} threads... // CHECK-NOT: warning: // CHECK-QUIET-NOT: warning: struct B : public A { diff --git a/clang-tools-extra/test/clang-tidy/infrastructure/clang-tidy-run-with-database.cpp b/clang-tools-extra/test/clang-tidy/infrastructure/clang-tidy-run-with-database.cpp index 3c4e849..9ca0ab3 100644 --- a/clang-tools-extra/test/clang-tidy/infrastructure/clang-tidy-run-with-database.cpp +++ b/clang-tools-extra/test/clang-tidy/infrastructure/clang-tidy-run-with-database.cpp @@ -1,28 +1,28 @@ -// RUN: mkdir -p %T/compilation-database-test/include -// RUN: mkdir -p %T/compilation-database-test/a -// RUN: mkdir -p %T/compilation-database-test/b -// RUN: echo 'int *AA = 0;' > %T/compilation-database-test/a/a.cpp -// RUN: echo 'int *AB = 0;' > %T/compilation-database-test/a/b.cpp -// RUN: echo 'int *BB = 0;' > %T/compilation-database-test/b/b.cpp -// RUN: echo 'int *BC = 0;' > %T/compilation-database-test/b/c.cpp -// RUN: echo 'int *BD = 0;' > %T/compilation-database-test/b/d.cpp -// RUN: echo 'int *HP = 0;' > %T/compilation-database-test/include/header.h -// RUN: echo '#include "header.h"' > %T/compilation-database-test/include.cpp -// RUN: sed 's|test_dir|%/T/compilation-database-test|g' %S/Inputs/compilation-database/template.json > %T/compile_commands.json +// RUN: mkdir -p %t.dir/compilation-database-test/include +// RUN: mkdir -p %t.dir/compilation-database-test/a +// RUN: mkdir -p %t.dir/compilation-database-test/b +// RUN: echo 'int *AA = 0;' > %t.dir/compilation-database-test/a/a.cpp +// RUN: echo 'int *AB = 0;' > %t.dir/compilation-database-test/a/b.cpp +// RUN: echo 'int *BB = 0;' > %t.dir/compilation-database-test/b/b.cpp +// RUN: echo 'int *BC = 0;' > %t.dir/compilation-database-test/b/c.cpp +// RUN: echo 'int *BD = 0;' > %t.dir/compilation-database-test/b/d.cpp +// RUN: echo 'int *HP = 0;' > %t.dir/compilation-database-test/include/header.h +// RUN: echo '#include "header.h"' > %t.dir/compilation-database-test/include.cpp +// RUN: sed 's|test_dir|%/t.dir/compilation-database-test|g' %S/Inputs/compilation-database/template.json > %t.dir/compile_commands.json // Regression test: shouldn't crash. -// RUN: not clang-tidy --checks=-*,modernize-use-nullptr -p %T %T/compilation-database-test/b/not-exist -header-filter=.* 2>&1 | FileCheck %s -check-prefix=CHECK-NOT-EXIST +// RUN: not clang-tidy --checks=-*,modernize-use-nullptr -p %t.dir %t.dir/compilation-database-test/b/not-exist -header-filter=.* 2>&1 | FileCheck %s -check-prefix=CHECK-NOT-EXIST // CHECK-NOT-EXIST: Error while processing {{.*[/\\]}}not-exist. // CHECK-NOT-EXIST: unable to handle compilation // CHECK-NOT-EXIST: Found compiler error -// RUN: clang-tidy --checks=-*,modernize-use-nullptr -p %T %T/compilation-database-test/a/a.cpp %T/compilation-database-test/a/b.cpp %T/compilation-database-test/b/b.cpp %T/compilation-database-test/b/c.cpp %T/compilation-database-test/b/d.cpp %T/compilation-database-test/include.cpp -header-filter=.* -fix -// RUN: FileCheck -input-file=%T/compilation-database-test/a/a.cpp %s -check-prefix=CHECK-FIX1 -// RUN: FileCheck -input-file=%T/compilation-database-test/a/b.cpp %s -check-prefix=CHECK-FIX2 -// RUN: FileCheck -input-file=%T/compilation-database-test/b/b.cpp %s -check-prefix=CHECK-FIX3 -// RUN: FileCheck -input-file=%T/compilation-database-test/b/c.cpp %s -check-prefix=CHECK-FIX4 -// RUN: FileCheck -input-file=%T/compilation-database-test/b/d.cpp %s -check-prefix=CHECK-FIX5 -// RUN: FileCheck -input-file=%T/compilation-database-test/include/header.h %s -check-prefix=CHECK-FIX6 +// RUN: clang-tidy --checks=-*,modernize-use-nullptr -p %t.dir %t.dir/compilation-database-test/a/a.cpp %t.dir/compilation-database-test/a/b.cpp %t.dir/compilation-database-test/b/b.cpp %t.dir/compilation-database-test/b/c.cpp %t.dir/compilation-database-test/b/d.cpp %t.dir/compilation-database-test/include.cpp -header-filter=.* -fix +// RUN: FileCheck -input-file=%t.dir/compilation-database-test/a/a.cpp %s -check-prefix=CHECK-FIX1 +// RUN: FileCheck -input-file=%t.dir/compilation-database-test/a/b.cpp %s -check-prefix=CHECK-FIX2 +// RUN: FileCheck -input-file=%t.dir/compilation-database-test/b/b.cpp %s -check-prefix=CHECK-FIX3 +// RUN: FileCheck -input-file=%t.dir/compilation-database-test/b/c.cpp %s -check-prefix=CHECK-FIX4 +// RUN: FileCheck -input-file=%t.dir/compilation-database-test/b/d.cpp %s -check-prefix=CHECK-FIX5 +// RUN: FileCheck -input-file=%t.dir/compilation-database-test/include/header.h %s -check-prefix=CHECK-FIX6 // CHECK-FIX1: int *AA = nullptr; // CHECK-FIX2: int *AB = nullptr; diff --git a/clang-tools-extra/test/clang-tidy/infrastructure/clang-tidy-store-check-profile-one-tu.cpp b/clang-tools-extra/test/clang-tidy/infrastructure/clang-tidy-store-check-profile-one-tu.cpp index f0939f7..192fbf5 100644 --- a/clang-tools-extra/test/clang-tidy/infrastructure/clang-tidy-store-check-profile-one-tu.cpp +++ b/clang-tools-extra/test/clang-tidy/infrastructure/clang-tidy-store-check-profile-one-tu.cpp @@ -1,9 +1,9 @@ -// RUN: rm -rf %T/out -// RUN: clang-tidy -enable-check-profile -checks='-*,readability-function-size' -store-check-profile=%T/out %s -- 2>&1 | not FileCheck --match-full-lines -implicit-check-not='{{warning:|error:}}' -check-prefix=CHECK-CONSOLE %s -// RUN: cat %T/out/*-clang-tidy-store-check-profile-one-tu.cpp.json | FileCheck --match-full-lines -implicit-check-not='{{warning:|error:}}' -check-prefix=CHECK-FILE %s -// RUN: rm -rf %T/out -// RUN: clang-tidy -enable-check-profile -checks='-*,readability-function-size' -store-check-profile=%T/out %s -- 2>&1 -// RUN: cat %T/out/*-clang-tidy-store-check-profile-one-tu.cpp.json | FileCheck --match-full-lines -implicit-check-not='{{warning:|error:}}' -check-prefix=CHECK-FILE %s +// RUN: rm -rf %t.dir/out +// RUN: clang-tidy -enable-check-profile -checks='-*,readability-function-size' -store-check-profile=%t.dir/out %s -- 2>&1 | not FileCheck --match-full-lines -implicit-check-not='{{warning:|error:}}' -check-prefix=CHECK-CONSOLE %s +// RUN: cat %t.dir/out/*-clang-tidy-store-check-profile-one-tu.cpp.json | FileCheck --match-full-lines -implicit-check-not='{{warning:|error:}}' -check-prefix=CHECK-FILE %s +// RUN: rm -rf %t.dir/out +// RUN: clang-tidy -enable-check-profile -checks='-*,readability-function-size' -store-check-profile=%t.dir/out %s -- 2>&1 +// RUN: cat %t.dir/out/*-clang-tidy-store-check-profile-one-tu.cpp.json | FileCheck --match-full-lines -implicit-check-not='{{warning:|error:}}' -check-prefix=CHECK-FILE %s // CHECK-CONSOLE-NOT: ===-------------------------------------------------------------------------=== // CHECK-CONSOLE-NOT: {{.*}} --- Name --- diff --git a/clang-tools-extra/test/clang-tidy/infrastructure/diagnostic.cpp b/clang-tools-extra/test/clang-tidy/infrastructure/diagnostic.cpp index 57d930b..610d1da 100644 --- a/clang-tools-extra/test/clang-tidy/infrastructure/diagnostic.cpp +++ b/clang-tools-extra/test/clang-tidy/infrastructure/diagnostic.cpp @@ -14,15 +14,15 @@ // Now create a directory with a compilation database file and ensure we don't // use it after failing to parse commands from the command line: // -// RUN: mkdir -p %T/diagnostics/ -// RUN: echo '[{"directory": "%/T/diagnostics/","command": "clang++ -fan-option-from-compilation-database -c %/T/diagnostics/input.cpp", "file": "%/T/diagnostics/input.cpp"}]' > %T/diagnostics/compile_commands.json -// RUN: cat %s > %T/diagnostics/input.cpp -// RUN: not clang-tidy -checks='-*,modernize-use-override' %T/diagnostics/nonexistent.cpp -- 2>&1 | FileCheck -check-prefix=CHECK1 -implicit-check-not='{{warning:|error:}}' %s -// RUN: not clang-tidy -checks='-*,clang-diagnostic-*,google-explicit-constructor' %T/diagnostics/input.cpp -- -fan-unknown-option 2>&1 | FileCheck -check-prefix=CHECK2 -implicit-check-not='{{warning:|error:}}' %s -// RUN: not clang-tidy -checks='-*,google-explicit-constructor,clang-diagnostic-literal-conversion' %T/diagnostics/input.cpp -- -fan-unknown-option 2>&1 | FileCheck -check-prefix=CHECK3 -implicit-check-not='{{warning:|error:}}' %s -// RUN: clang-tidy -checks='-*,modernize-use-override,clang-diagnostic-macro-redefined' %T/diagnostics/input.cpp -- -DMACRO_FROM_COMMAND_LINE 2>&1 | FileCheck -check-prefix=CHECK4 -implicit-check-not='{{warning:|error:}}' %s -// RUN: not clang-tidy -checks='-*,clang-diagnostic-*,google-explicit-constructor' %T/diagnostics/input.cpp 2>&1 | FileCheck -check-prefix=CHECK5 -implicit-check-not='{{warning:|error:}}' %s -// RUN: not clang-tidy -checks='-*,modernize-use-override' %T/diagnostics/input.cpp -- -DCOMPILATION_ERROR 2>&1 | FileCheck -check-prefix=CHECK6 -implicit-check-not='{{warning:|error:}}' %s +// RUN: mkdir -p %t.dir/diagnostics/ +// RUN: echo '[{"directory": "%/t.dir/diagnostics/","command": "clang++ -fan-option-from-compilation-database -c %/T/diagnostics/input.cpp", "file": "%/T/diagnostics/input.cpp"}]' > %t.dir/diagnostics/compile_commands.json +// RUN: cat %s > %t.dir/diagnostics/input.cpp +// RUN: not clang-tidy -checks='-*,modernize-use-override' %t.dir/diagnostics/nonexistent.cpp -- 2>&1 | FileCheck -check-prefix=CHECK1 -implicit-check-not='{{warning:|error:}}' %s +// RUN: not clang-tidy -checks='-*,clang-diagnostic-*,google-explicit-constructor' %t.dir/diagnostics/input.cpp -- -fan-unknown-option 2>&1 | FileCheck -check-prefix=CHECK2 -implicit-check-not='{{warning:|error:}}' %s +// RUN: not clang-tidy -checks='-*,google-explicit-constructor,clang-diagnostic-literal-conversion' %t.dir/diagnostics/input.cpp -- -fan-unknown-option 2>&1 | FileCheck -check-prefix=CHECK3 -implicit-check-not='{{warning:|error:}}' %s +// RUN: clang-tidy -checks='-*,modernize-use-override,clang-diagnostic-macro-redefined' %t.dir/diagnostics/input.cpp -- -DMACRO_FROM_COMMAND_LINE 2>&1 | FileCheck -check-prefix=CHECK4 -implicit-check-not='{{warning:|error:}}' %s +// RUN: not clang-tidy -checks='-*,clang-diagnostic-*,google-explicit-constructor' %t.dir/diagnostics/input.cpp 2>&1 | FileCheck -check-prefix=CHECK5 -implicit-check-not='{{warning:|error:}}' %s +// RUN: not clang-tidy -checks='-*,modernize-use-override' %t.dir/diagnostics/input.cpp -- -DCOMPILATION_ERROR 2>&1 | FileCheck -check-prefix=CHECK6 -implicit-check-not='{{warning:|error:}}' %s // RUN: clang-tidy -checks='-*,modernize-use-override,clang-diagnostic-macro-redefined' %s -- -DMACRO_FROM_COMMAND_LINE -std=c++20 | FileCheck -check-prefix=CHECK4 -implicit-check-not='{{warning:|error:}}' %s // RUN: clang-tidy -checks='-*,modernize-use-override,clang-diagnostic-macro-redefined,clang-diagnostic-literal-conversion' %s -- -DMACRO_FROM_COMMAND_LINE -std=c++20 -Wno-macro-redefined | FileCheck --check-prefix=CHECK7 -implicit-check-not='{{warning:|error:}}' %s // RUN: clang-tidy -checks='-*,modernize-use-override' %s -- -std=c++20 -DPR64602 diff --git a/clang-tools-extra/test/clang-tidy/infrastructure/export-relpath.cpp b/clang-tools-extra/test/clang-tidy/infrastructure/export-relpath.cpp index 5bfd41f..5fd7303 100644 --- a/clang-tools-extra/test/clang-tidy/infrastructure/export-relpath.cpp +++ b/clang-tools-extra/test/clang-tidy/infrastructure/export-relpath.cpp @@ -1,14 +1,15 @@ -// RUN: rm -rf %T/clang-tidy/export-relpath -// RUN: mkdir -p %T/clang-tidy/export-relpath/subdir -// RUN: cp %s %T/clang-tidy/export-relpath/subdir/source.cpp -// RUN: echo '[{ "directory": "%/T/clang-tidy/export-relpath/subdir", "command": "clang++ source.cpp", "file": "%/T/clang-tidy/export-relpath/subdir/source.cpp"}]' > %T/clang-tidy/export-relpath/subdir/compile_commands.json +// RUN: mkdir -p %t.dir +// RUN: rm -rf %t.dir/clang-tidy/export-relpath +// RUN: mkdir -p %t.dir/clang-tidy/export-relpath/subdir +// RUN: cp %s %t.dir/clang-tidy/export-relpath/subdir/source.cpp +// RUN: echo '[{ "directory": "%/t.dir/clang-tidy/export-relpath/subdir", "command": "clang++ source.cpp", "file": "%/T/clang-tidy/export-relpath/subdir/source.cpp"}]' > %t.dir/clang-tidy/export-relpath/subdir/compile_commands.json // // Check that running clang-tidy in './subdir' and storing results // in './fixes.yaml' works as expected. // -// RUN: cd %T/clang-tidy/export-relpath +// RUN: cd %t.dir/clang-tidy/export-relpath // RUN: clang-tidy -p subdir subdir/source.cpp -checks='-*,google-explicit-constructor,llvm-namespace-comment' -export-fixes=./fixes.yaml -// RUN: FileCheck -input-file=%T/clang-tidy/export-relpath/fixes.yaml -check-prefix=CHECK-YAML %s +// RUN: FileCheck -input-file=%t.dir/clang-tidy/export-relpath/fixes.yaml -check-prefix=CHECK-YAML %s namespace i { void f(); // So that the namespace isn't empty. diff --git a/clang-tools-extra/test/clang-tidy/infrastructure/list-checks.cpp b/clang-tools-extra/test/clang-tidy/infrastructure/list-checks.cpp index 674c118..73bb5b7 100644 --- a/clang-tools-extra/test/clang-tidy/infrastructure/list-checks.cpp +++ b/clang-tools-extra/test/clang-tidy/infrastructure/list-checks.cpp @@ -1,4 +1,4 @@ -// RUN: mkdir -p %T/clang-tidy/list-checks/ -// RUN: echo '{Checks: "-*,google-*"}' > %T/clang-tidy/.clang-tidy -// RUN: cd %T/clang-tidy/list-checks +// RUN: mkdir -p %t.dir/clang-tidy/list-checks/ +// RUN: echo '{Checks: "-*,google-*"}' > %t.dir/clang-tidy/.clang-tidy +// RUN: cd %t.dir/clang-tidy/list-checks // RUN: clang-tidy -list-checks | grep "^ *google-" diff --git a/clang-tools-extra/test/clang-tidy/infrastructure/read_file_config.cpp b/clang-tools-extra/test/clang-tidy/infrastructure/read_file_config.cpp index 3e39b4d..8b12f45 100644 --- a/clang-tools-extra/test/clang-tidy/infrastructure/read_file_config.cpp +++ b/clang-tools-extra/test/clang-tidy/infrastructure/read_file_config.cpp @@ -1,10 +1,10 @@ // REQUIRES: static-analyzer -// RUN: mkdir -p %T/read-file-config/ -// RUN: cp %s %T/read-file-config/test.cpp -// RUN: echo 'Checks: "-*,modernize-use-nullptr"' > %T/read-file-config/.clang-tidy -// RUN: echo '[{"command": "cc -c -o test.o test.cpp", "directory": "%/T/read-file-config", "file": "%/T/read-file-config/test.cpp"}]' > %T/read-file-config/compile_commands.json -// RUN: clang-tidy %T/read-file-config/test.cpp | not grep "warning: .*\[clang-analyzer-deadcode.DeadStores\]$" -// RUN: clang-tidy -checks="-*,clang-analyzer-*" %T/read-file-config/test.cpp | grep "warning: .*\[clang-analyzer-deadcode.DeadStores\]$" +// RUN: mkdir -p %t.dir/read-file-config/ +// RUN: cp %s %t.dir/read-file-config/test.cpp +// RUN: echo 'Checks: "-*,modernize-use-nullptr"' > %t.dir/read-file-config/.clang-tidy +// RUN: echo '[{"command": "cc -c -o test.o test.cpp", "directory": "%/t.dir/read-file-config", "file": "%/t.dir/read-file-config/test.cpp"}]' > %t.dir/read-file-config/compile_commands.json +// RUN: clang-tidy %t.dir/read-file-config/test.cpp | not grep "warning: .*\[clang-analyzer-deadcode.DeadStores\]$" +// RUN: clang-tidy -checks="-*,clang-analyzer-*" %t.dir/read-file-config/test.cpp | grep "warning: .*\[clang-analyzer-deadcode.DeadStores\]$" void f() { int x; diff --git a/clang-tools-extra/test/clang-tidy/infrastructure/run-clang-tidy.cpp b/clang-tools-extra/test/clang-tidy/infrastructure/run-clang-tidy.cpp index 505ee28..6337686 100644 --- a/clang-tools-extra/test/clang-tidy/infrastructure/run-clang-tidy.cpp +++ b/clang-tools-extra/test/clang-tidy/infrastructure/run-clang-tidy.cpp @@ -8,7 +8,11 @@ // RUN: echo " modernize-use-auto.MinTypeNameLength: '0'" >> %t/.clang-tidy // RUN: cp "%s" "%t/test.cpp" // RUN: cd "%t" -// RUN: not %run_clang_tidy "test.cpp" +// RUN: not %run_clang_tidy "test.cpp" 2>&1 | FileCheck %s --check-prefix=CHECK-JMAX +// CHECK-JMAX: Running clang-tidy in {{[1-9][0-9]*}} threads for + +// RUN: not %run_clang_tidy -j 1 "test.cpp" 2>&1 | FileCheck %s --check-prefix=CHECK-J1 +// CHECK-J1: Running clang-tidy in 1 threads for int main() { diff --git a/clang-tools-extra/test/clang-tidy/infrastructure/static-analyzer-config.cpp b/clang-tools-extra/test/clang-tidy/infrastructure/static-analyzer-config.cpp index 725f877..6a9641e 100644 --- a/clang-tools-extra/test/clang-tidy/infrastructure/static-analyzer-config.cpp +++ b/clang-tools-extra/test/clang-tidy/infrastructure/static-analyzer-config.cpp @@ -16,5 +16,5 @@ void af2() { void *p = my_malloc(12); my_free(p); free(p); - // CHECK: warning: Attempt to free released memory [clang-analyzer-unix.Malloc] + // CHECK: warning: Attempt to release already released memory [clang-analyzer-unix.Malloc] } diff --git a/clang-tools-extra/test/clang-tidy/infrastructure/static-analyzer.cpp b/clang-tools-extra/test/clang-tidy/infrastructure/static-analyzer.cpp index af9693a..c45f219 100644 --- a/clang-tools-extra/test/clang-tidy/infrastructure/static-analyzer.cpp +++ b/clang-tools-extra/test/clang-tidy/infrastructure/static-analyzer.cpp @@ -7,12 +7,12 @@ void f() { int *p = new int(42); delete p; delete p; - // CHECK: warning: Attempt to free released memory [clang-analyzer-cplusplus.NewDelete] + // CHECK: warning: Attempt to release already released memory [clang-analyzer-cplusplus.NewDelete] } void g() { void *q = malloc(132); free(q); free(q); - // CHECK: warning: Attempt to free released memory [clang-analyzer-unix.Malloc] + // CHECK: warning: Attempt to release already released memory [clang-analyzer-unix.Malloc] } diff --git a/clang-tools-extra/test/clang-tidy/infrastructure/verify-config.cpp b/clang-tools-extra/test/clang-tidy/infrastructure/verify-config.cpp index 93f6f9f..30d4933 100644 --- a/clang-tools-extra/test/clang-tidy/infrastructure/verify-config.cpp +++ b/clang-tools-extra/test/clang-tidy/infrastructure/verify-config.cpp @@ -19,22 +19,22 @@ // CHECK-VERIFY: command-line option '-checks': warning: unknown check 'llvm-includeorder'; did you mean 'llvm-include-order' [-verify-config] // CHECK-VERIFY: command-line option '-checks': warning: unknown check 'my-made-up-check' [-verify-config] -// RUN: echo -e 'Checks: |\n bugprone-argument-comment\n bugprone-assert-side-effect,\n bugprone-bool-pointer-implicit-conversion\n readability-use-anyof*' > %T/MyClangTidyConfig +// RUN: echo -e 'Checks: |\n bugprone-argument-comment\n bugprone-assert-side-effect,\n bugprone-bool-pointer-implicit-conversion\n readability-use-anyof*' > %t.MyClangTidyConfig // RUN: clang-tidy -verify-config \ -// RUN: --config-file=%T/MyClangTidyConfig | FileCheck %s -check-prefix=CHECK-VERIFY-BLOCK-OK +// RUN: --config-file=%t.MyClangTidyConfig | FileCheck %s -check-prefix=CHECK-VERIFY-BLOCK-OK // CHECK-VERIFY-BLOCK-OK: No config errors detected. -// RUN: echo -e 'Checks: |\n bugprone-arguments-*\n bugprone-assert-side-effects\n bugprone-bool-pointer-implicit-conversion' > %T/MyClangTidyConfigBad +// RUN: echo -e 'Checks: |\n bugprone-arguments-*\n bugprone-assert-side-effects\n bugprone-bool-pointer-implicit-conversion' > %t.MyClangTidyConfigBad // RUN: not clang-tidy -verify-config \ -// RUN: --config-file=%T/MyClangTidyConfigBad 2>&1 | FileCheck %s -check-prefix=CHECK-VERIFY-BLOCK-BAD +// RUN: --config-file=%t.MyClangTidyConfigBad 2>&1 | FileCheck %s -check-prefix=CHECK-VERIFY-BLOCK-BAD // CHECK-VERIFY-BLOCK-BAD: command-line option '-config': warning: check glob 'bugprone-arguments-*' doesn't match any known check [-verify-config] // CHECK-VERIFY-BLOCK-BAD: command-line option '-config': warning: unknown check 'bugprone-assert-side-effects'; did you mean 'bugprone-assert-side-effect' [-verify-config] -// RUN: echo -e 'Checks: "-*,clang-analyzer-optin.cplusplus.UninitializedObject"\nCheckOptions:\n clang-analyzer-optin.cplusplus.UninitializedObject:Pedantic: true' > %T/MyClangTidyConfigCSA -// RUN: clang-tidy --verify-config --config-file=%T/MyClangTidyConfigCSA 2>&1 | FileCheck %s -check-prefix=CHECK-VERIFY-CSA-OK -implicit-check-not='{{warnings|error}}' +// RUN: echo -e 'Checks: "-*,clang-analyzer-optin.cplusplus.UninitializedObject"\nCheckOptions:\n clang-analyzer-optin.cplusplus.UninitializedObject:Pedantic: true' > %t.MyClangTidyConfigCSA +// RUN: clang-tidy --verify-config --config-file=%t.MyClangTidyConfigCSA 2>&1 | FileCheck %s -check-prefix=CHECK-VERIFY-CSA-OK -implicit-check-not='{{warnings|error}}' // CHECK-VERIFY-CSA-OK: No config errors detected. -// RUN: echo -e 'Checks: "-*,clang-analyzer-optin.cplusplus.UninitializedObject"\nCheckOptions:\n clang-analyzer-optin.cplusplus.UninitializedObject.Pedantic: true' > %T/MyClangTidyConfigCSABad -// RUN: not clang-tidy --verify-config --config-file=%T/MyClangTidyConfigCSABad 2>&1 | FileCheck %s -check-prefix=CHECK-VERIFY-CSA-BAD -implicit-check-not='{{warnings|error}}' +// RUN: echo -e 'Checks: "-*,clang-analyzer-optin.cplusplus.UninitializedObject"\nCheckOptions:\n clang-analyzer-optin.cplusplus.UninitializedObject.Pedantic: true' > %t.MyClangTidyConfigCSABad +// RUN: not clang-tidy --verify-config --config-file=%t.MyClangTidyConfigCSABad 2>&1 | FileCheck %s -check-prefix=CHECK-VERIFY-CSA-BAD -implicit-check-not='{{warnings|error}}' // CHECK-VERIFY-CSA-BAD: command-line option '-config': warning: unknown check option 'clang-analyzer-optin.cplusplus.UninitializedObject.Pedantic'; did you mean 'clang-analyzer-optin.cplusplus.UninitializedObject:Pedantic' [-verify-config] diff --git a/clang-tools-extra/test/modularize/NoProblemsAssistant.modularize b/clang-tools-extra/test/modularize/NoProblemsAssistant.modularize index 7ddc726..39c06dc 100644 --- a/clang-tools-extra/test/modularize/NoProblemsAssistant.modularize +++ b/clang-tools-extra/test/modularize/NoProblemsAssistant.modularize @@ -1,5 +1,7 @@ +# RUN: mkdir -p %t.dir/Output +# RUN: cd %t.dir # RUN: modularize -module-map-path=Output/NoProblemsAssistant.txt -root-module=Root -prefix=%S/Input %s -# RUN: FileCheck --input-file=%T/NoProblemsAssistant.txt %s +# RUN: FileCheck --input-file=Output/NoProblemsAssistant.txt %s SomeTypes.h SomeDecls.h diff --git a/clang-tools-extra/unittests/clang-apply-replacements/ApplyReplacementsTest.cpp b/clang-tools-extra/unittests/clang-apply-replacements/ApplyReplacementsTest.cpp index 87b0d69..0b92118 100644 --- a/clang-tools-extra/unittests/clang-apply-replacements/ApplyReplacementsTest.cpp +++ b/clang-tools-extra/unittests/clang-apply-replacements/ApplyReplacementsTest.cpp @@ -33,8 +33,7 @@ makeTUDiagnostics(const std::string &MainSourceFile, StringRef DiagnosticName, // before applying. TEST(ApplyReplacementsTest, mergeDiagnosticsWithNoFixes) { DiagnosticOptions DiagOpts; - DiagnosticsEngine Diagnostics( - IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), DiagOpts); + DiagnosticsEngine Diagnostics(DiagnosticIDs::create(), DiagOpts); FileManager Files((FileSystemOptions())); SourceManager SM(Diagnostics, Files); TUReplacements TURs; diff --git a/clang-tools-extra/unittests/clang-doc/HTMLMustacheGeneratorTest.cpp b/clang-tools-extra/unittests/clang-doc/HTMLMustacheGeneratorTest.cpp index 32b0846..602058f 100644 --- a/clang-tools-extra/unittests/clang-doc/HTMLMustacheGeneratorTest.cpp +++ b/clang-tools-extra/unittests/clang-doc/HTMLMustacheGeneratorTest.cpp @@ -86,132 +86,3 @@ TEST(HTMLMustacheGeneratorTest, createResources) { verifyFileContents(PathBuf, "JavaScript"); } } - -TEST(HTMLGeneratorTest, emitFunctionHTML) { -#if ENABLE_LOCAL_TEST - auto G = getHTMLMustacheGenerator(); - assert(G && "Could not find HTMLMustacheGenerator"); - ClangDocContext CDCtx = getClangDocContext(); - std::string Buffer; - llvm::raw_string_ostream Actual(Buffer); - - unittest::TempDir RootTestDirectory("emitRecordHTML", - /*Unique=*/true); - CDCtx.OutDirectory = RootTestDirectory.path(); - - getMustacheHtmlFiles(CLANG_DOC_TEST_ASSET_DIR, CDCtx); - - // FIXME: This is a terrible hack, since we can't initialize the templates - // directly. We'll need to update the interfaces so that we can call - // SetupTemplateFiles() from outsize of HTMLMustacheGenerator.cpp - EXPECT_THAT_ERROR(G->generateDocs(RootTestDirectory.path(), {}, CDCtx), - Succeeded()) - << "Failed to generate docs."; - - CDCtx.RepositoryUrl = "http://www.repository.com"; - - FunctionInfo I; - I.Name = "f"; - I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace); - - I.DefLoc = Location(10, 10, "dir/test.cpp", true); - I.Loc.emplace_back(12, 12, "test.cpp"); - - I.Access = AccessSpecifier::AS_none; - - SmallString<16> PathTo; - llvm::sys::path::native("path/to", PathTo); - I.ReturnType = doc::TypeInfo( - Reference(EmptySID, "float", InfoType::IT_default, "float", PathTo)); - I.Params.emplace_back(doc::TypeInfo("int", PathTo), "P"); - I.IsMethod = true; - I.Parent = Reference(EmptySID, "Parent", InfoType::IT_record); - - auto Err = G->generateDocForInfo(&I, Actual, CDCtx); - assert(!Err); - std::string Expected = R"raw(IT_Function -)raw"; - - // FIXME: Functions are not handled yet. - EXPECT_EQ(Expected, Actual.str()); -#endif -} - -TEST(HTMLMustacheGeneratorTest, emitCommentHTML) { -#if ENABLE_LOCAL_TEST - auto G = getHTMLMustacheGenerator(); - assert(G && "Could not find HTMLMustacheGenerator"); - ClangDocContext CDCtx = getClangDocContext(); - std::string Buffer; - llvm::raw_string_ostream Actual(Buffer); - - unittest::TempDir RootTestDirectory("emitCommentHTML", - /*Unique=*/true); - CDCtx.OutDirectory = RootTestDirectory.path(); - - getMustacheHtmlFiles(CLANG_DOC_TEST_ASSET_DIR, CDCtx); - - // FIXME: This is a terrible hack, since we can't initialize the templates - // directly. We'll need to update the interfaces so that we can call - // SetupTemplateFiles() from outsize of HTMLMustacheGenerator.cpp - EXPECT_THAT_ERROR(G->generateDocs(RootTestDirectory.path(), {}, CDCtx), - Succeeded()) - << "Failed to generate docs."; - - CDCtx.RepositoryUrl = "http://www.repository.com"; - - FunctionInfo I; - I.Name = "f"; - I.DefLoc = Location(10, 10, "test.cpp", true); - I.ReturnType = doc::TypeInfo("void"); - I.Params.emplace_back(doc::TypeInfo("int"), "I"); - I.Params.emplace_back(doc::TypeInfo("int"), "J"); - I.Access = AccessSpecifier::AS_none; - - CommentInfo Top; - Top.Kind = "FullComment"; - - Top.Children.emplace_back(std::make_unique<CommentInfo>()); - CommentInfo *BlankLine = Top.Children.back().get(); - BlankLine->Kind = "ParagraphComment"; - BlankLine->Children.emplace_back(std::make_unique<CommentInfo>()); - BlankLine->Children.back()->Kind = "TextComment"; - - Top.Children.emplace_back(std::make_unique<CommentInfo>()); - CommentInfo *Brief = Top.Children.back().get(); - Brief->Kind = "ParagraphComment"; - Brief->Children.emplace_back(std::make_unique<CommentInfo>()); - Brief->Children.back()->Kind = "TextComment"; - Brief->Children.back()->Name = "ParagraphComment"; - Brief->Children.back()->Text = " Brief description."; - - Top.Children.emplace_back(std::make_unique<CommentInfo>()); - CommentInfo *Extended = Top.Children.back().get(); - Extended->Kind = "ParagraphComment"; - Extended->Children.emplace_back(std::make_unique<CommentInfo>()); - Extended->Children.back()->Kind = "TextComment"; - Extended->Children.back()->Text = " Extended description that"; - Extended->Children.emplace_back(std::make_unique<CommentInfo>()); - Extended->Children.back()->Kind = "TextComment"; - Extended->Children.back()->Text = " continues onto the next line."; - - Top.Children.emplace_back(std::make_unique<CommentInfo>()); - CommentInfo *Entities = Top.Children.back().get(); - Entities->Kind = "ParagraphComment"; - Entities->Children.emplace_back(std::make_unique<CommentInfo>()); - Entities->Children.back()->Kind = "TextComment"; - Entities->Children.back()->Name = "ParagraphComment"; - Entities->Children.back()->Text = - " Comment with html entities: &, <, >, \", \'."; - - I.Description.emplace_back(std::move(Top)); - - auto Err = G->generateDocForInfo(&I, Actual, CDCtx); - assert(!Err); - std::string Expected = R"raw(IT_Function -)raw"; - - // FIXME: Functions are not handled yet. - EXPECT_EQ(Expected, Actual.str()); -#endif -} diff --git a/clang-tools-extra/unittests/clang-doc/JSONGeneratorTest.cpp b/clang-tools-extra/unittests/clang-doc/JSONGeneratorTest.cpp index 5927235b..07c761f 100644 --- a/clang-tools-extra/unittests/clang-doc/JSONGeneratorTest.cpp +++ b/clang-tools-extra/unittests/clang-doc/JSONGeneratorTest.cpp @@ -63,7 +63,11 @@ TEST(JSONGeneratorTest, emitRecordJSON) { "Bases": [ { "Access": "public", + "End": true, "FullName": "", + "HasPublicFunctions": true, + "HasPublicMembers": true, + "InfoType": "record", "IsParent": true, "IsTypedef": false, "IsVirtual": true, @@ -72,6 +76,7 @@ TEST(JSONGeneratorTest, emitRecordJSON) { "Path": "path/to/F", "PublicFunctions": [ { + "InfoType": "function", "IsStatic": false, "Name": "InheritedFunctionOne", "ReturnType": { @@ -96,8 +101,11 @@ TEST(JSONGeneratorTest, emitRecordJSON) { ], "Enums": [ { + "End": true, + "InfoType": "enum", "Members": [ { + "End": true, "Name": "RED", "Value": "0" } @@ -108,6 +116,10 @@ TEST(JSONGeneratorTest, emitRecordJSON) { } ], "FullName": "", + "HasEnums": true, + "HasPublicFunctions": true, + "HasRecords": true, + "InfoType": "record", "IsTypedef": false, "Location": { "Filename": "main.cpp", @@ -120,6 +132,7 @@ TEST(JSONGeneratorTest, emitRecordJSON) { ], "Parents": [ { + "End": true, "Name": "F", "Path": "", "QualName": "", @@ -135,6 +148,7 @@ TEST(JSONGeneratorTest, emitRecordJSON) { ], "PublicFunctions": [ { + "InfoType": "function", "IsStatic": false, "Name": "OneFunction", "ReturnType": { @@ -149,6 +163,7 @@ TEST(JSONGeneratorTest, emitRecordJSON) { ], "Records": [ { + "End": true, "Name": "ChildStruct", "Path": "path/to/A/r", "QualName": "path::to::A::r::ChildStruct", @@ -164,6 +179,7 @@ TEST(JSONGeneratorTest, emitRecordJSON) { "USR": "0000000000000000000000000000000000000000", "VirtualParents": [ { + "End": true, "Name": "G", "Path": "path/to/G", "QualName": "path::to::G::G", @@ -201,6 +217,8 @@ TEST(JSONGeneratorTest, emitNamespaceJSON) { std::string Expected = R"raw({ "Enums": [ { + "End": true, + "InfoType": "enum", "Name": "OneEnum", "Scoped": false, "USR": "0000000000000000000000000000000000000000" @@ -208,6 +226,8 @@ TEST(JSONGeneratorTest, emitNamespaceJSON) { ], "Functions": [ { + "End": true, + "InfoType": "function", "IsStatic": false, "Name": "OneFunction", "ReturnType": { @@ -220,12 +240,16 @@ TEST(JSONGeneratorTest, emitNamespaceJSON) { "USR": "0000000000000000000000000000000000000000" } ], + "HasEnums": true, + "HasRecords": true, + "InfoType": "namespace", "Name": "Namespace", "Namespace": [ "A" ], "Namespaces": [ { + "End": true, "Name": "ChildNamespace", "Path": "path/to/A/Namespace", "QualName": "path::to::A::Namespace::ChildNamespace", @@ -235,6 +259,7 @@ TEST(JSONGeneratorTest, emitNamespaceJSON) { "Path": "path/to/A", "Records": [ { + "End": true, "Name": "ChildStruct", "Path": "path/to/A/Namespace", "QualName": "path::to::A::Namespace::ChildStruct", diff --git a/clang-tools-extra/unittests/clang-tidy/ClangTidyOptionsTest.cpp b/clang-tools-extra/unittests/clang-tidy/ClangTidyOptionsTest.cpp index d3ca26a..410cebf 100644 --- a/clang-tools-extra/unittests/clang-tidy/ClangTidyOptionsTest.cpp +++ b/clang-tools-extra/unittests/clang-tidy/ClangTidyOptionsTest.cpp @@ -318,7 +318,8 @@ TEST(CheckOptionsValidation, MissingOptions) { ClangTidyGlobalOptions(), Options)); ClangTidyDiagnosticConsumer DiagConsumer(Context); auto DiagOpts = std::make_unique<DiagnosticOptions>(); - DiagnosticsEngine DE(new DiagnosticIDs(), *DiagOpts, &DiagConsumer, false); + DiagnosticsEngine DE(DiagnosticIDs::create(), *DiagOpts, &DiagConsumer, + false); Context.setDiagnosticsEngine(std::move(DiagOpts), &DE); TestCheck TestCheck(&Context); EXPECT_FALSE(TestCheck.getLocal("Opt")); @@ -348,7 +349,8 @@ TEST(CheckOptionsValidation, ValidIntOptions) { ClangTidyGlobalOptions(), Options)); ClangTidyDiagnosticConsumer DiagConsumer(Context); auto DiagOpts = std::make_unique<DiagnosticOptions>(); - DiagnosticsEngine DE(new DiagnosticIDs(), *DiagOpts, &DiagConsumer, false); + DiagnosticsEngine DE(DiagnosticIDs::create(), *DiagOpts, &DiagConsumer, + false); Context.setDiagnosticsEngine(std::move(DiagOpts), &DE); TestCheck TestCheck(&Context); @@ -410,7 +412,8 @@ TEST(ValidConfiguration, ValidEnumOptions) { ClangTidyGlobalOptions(), Options)); ClangTidyDiagnosticConsumer DiagConsumer(Context); auto DiagOpts = std::make_unique<DiagnosticOptions>(); - DiagnosticsEngine DE(new DiagnosticIDs(), *DiagOpts, &DiagConsumer, false); + DiagnosticsEngine DE(DiagnosticIDs::create(), *DiagOpts, &DiagConsumer, + false); Context.setDiagnosticsEngine(std::move(DiagOpts), &DE); TestCheck TestCheck(&Context); diff --git a/clang-tools-extra/unittests/clang-tidy/ClangTidyTest.h b/clang-tools-extra/unittests/clang-tidy/ClangTidyTest.h index 789cc2a..89f0f9f 100644 --- a/clang-tools-extra/unittests/clang-tidy/ClangTidyTest.h +++ b/clang-tools-extra/unittests/clang-tidy/ClangTidyTest.h @@ -97,7 +97,8 @@ runCheckOnCode(StringRef Code, std::vector<ClangTidyError> *Errors = nullptr, ClangTidyGlobalOptions(), Options)); ClangTidyDiagnosticConsumer DiagConsumer(Context); auto DiagOpts = std::make_unique<DiagnosticOptions>(); - DiagnosticsEngine DE(new DiagnosticIDs(), *DiagOpts, &DiagConsumer, false); + DiagnosticsEngine DE(DiagnosticIDs::create(), *DiagOpts, &DiagConsumer, + false); Context.setDiagnosticsEngine(std::move(DiagOpts), &DE); std::vector<std::string> Args(1, "clang-tidy"); diff --git a/clang-tools-extra/unittests/include/common/VirtualFileHelper.h b/clang-tools-extra/unittests/include/common/VirtualFileHelper.h index 86991bb3..cb075f8 100644 --- a/clang-tools-extra/unittests/include/common/VirtualFileHelper.h +++ b/clang-tools-extra/unittests/include/common/VirtualFileHelper.h @@ -32,8 +32,7 @@ class VirtualFileHelper { public: VirtualFileHelper() - : Diagnostics(IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), - DiagOpts), + : Diagnostics(DiagnosticIDs::create(), DiagOpts), DiagnosticPrinter(llvm::outs(), DiagOpts), Files((FileSystemOptions())) {} |